* Re: [PATCH] slub: fix kernel BUG at mm/slub.c:1950!
From: Pekka Enberg @ 2011-06-13 18:34 UTC (permalink / raw)
To: Christoph Lameter; +Cc: linux-mm, linuxppc-dev, Hugh Dickins, linux-kernel
In-Reply-To: <alpine.DEB.2.00.1106131258300.3108@router.home>
On Mon, 2011-06-13 at 12:59 -0500, Christoph Lameter wrote:
> On Sun, 12 Jun 2011, Hugh Dickins wrote:
>
> > 3.0-rc won't boot with SLUB on my PowerPC G5: kernel BUG at mm/slub.c:1950!
> > Bisected to 1759415e630e "slub: Remove CONFIG_CMPXCHG_LOCAL ifdeffery".
> >
> > After giving myself a medal for finding the BUG on line 1950 of mm/slub.c
> > (it's actually the
> > VM_BUG_ON((unsigned long)(&pcp1) % (2 * sizeof(pcp1)));
> > on line 268 of the morass that is include/linux/percpu.h)
> > I tried the following alignment patch and found it to work.
>
> Hmmm.. The allocpercpu in alloc_kmem_cache_cpus should take care of the
> alignment. Uhh.. I see that a patch that removes the #ifdef CMPXCHG_LOCAL
> was not applied? Pekka?
This patch?
http://git.kernel.org/?p=linux/kernel/git/penberg/slab-2.6.git;a=commitdiff;h=d4d84fef6d0366b585b7de13527a0faeca84d9ce
It's queued and will be sent to Linus soon.
Pekka
^ permalink raw reply
* RE: [PATCH] usb:gadget: use min_t() macro instead of min()
From: Tanya Brokhman @ 2011-06-13 18:07 UTC (permalink / raw)
To: 'Alan Stern'
Cc: 'open list:FREESCALE USB PER...', greg, linux-usb,
'open list', balbi, linux-arm-msm,
'open list:OMAP USB SUPPORT', ablay
In-Reply-To: <Pine.LNX.4.44L0.1106131036430.1983-100000@iolanthe.rowland.org>
>
> The change I suggested involved replacing two typecasts with a single
> min_t. All (or almost all) the places this patch touches currently
> contain only one typecast, so the motivation for changing them is a lot
> weaker.
>
You're right. So what's the final call on this one? Do you think it can be
merged or you prefer not change anything? I personally think the code looks
nicer using min_t instead of min with casting but that's just my opinion and
of course there are arguments against this patch.
Thanks,
Tanya Brokhman
---
Sent by an consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* Re: [PATCH] slub: fix kernel BUG at mm/slub.c:1950!
From: Christoph Lameter @ 2011-06-13 17:59 UTC (permalink / raw)
To: Hugh Dickins; +Cc: linux-mm, Pekka Enberg, linuxppc-dev, linux-kernel
In-Reply-To: <alpine.LSU.2.00.1106121842250.31463@sister.anvils>
On Sun, 12 Jun 2011, Hugh Dickins wrote:
> 3.0-rc won't boot with SLUB on my PowerPC G5: kernel BUG at mm/slub.c:1950!
> Bisected to 1759415e630e "slub: Remove CONFIG_CMPXCHG_LOCAL ifdeffery".
>
> After giving myself a medal for finding the BUG on line 1950 of mm/slub.c
> (it's actually the
> VM_BUG_ON((unsigned long)(&pcp1) % (2 * sizeof(pcp1)));
> on line 268 of the morass that is include/linux/percpu.h)
> I tried the following alignment patch and found it to work.
Hmmm.. The allocpercpu in alloc_kmem_cache_cpus should take care of the
alignment. Uhh.. I see that a patch that removes the #ifdef CMPXCHG_LOCAL
was not applied? Pekka?
^ permalink raw reply
* RE: [PATCH] usb:gadget: use min_t() macro instead of min()
From: Alan Stern @ 2011-06-13 14:38 UTC (permalink / raw)
To: Tanya Brokhman
Cc: 'open list:FREESCALE USB PER...', greg, linux-usb,
'open list', balbi, linux-arm-msm,
'open list:OMAP USB SUPPORT', ablay
In-Reply-To: <03b901cc29c0$6538e970$2faabc50$@org>
On Mon, 13 Jun 2011, Tanya Brokhman wrote:
> >
> > On Sun, Jun 12, 2011 at 02:14:46PM +0300, Tatyana Brokhman wrote:
> > > Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
> >
> > I need a sensible commit log for this. Why do we need to change all
> > min() to min_t() ?
> >
>
> Actually, Alan asked me to make this change in one place in dummy_hcd. I
> wasn't aware of the min_t macro before that. So when I searched the code for
> other places I found quite a few and just thought that it would be "nicer"
> to use min_t() instead of min() with casting.
> So we don't "need" to make this change. Everything works as is. This patch
> only makes the code look nicer, nothing more.
> I can elaborate the above in the commit log if you want.
The change I suggested involved replacing two typecasts with a single
min_t. All (or almost all) the places this patch touches currently
contain only one typecast, so the motivation for changing them is a lot
weaker.
Alan Stern
^ permalink raw reply
* Re: [PATCH] usb:gadget: use min_t() macro instead of min()
From: Felipe Balbi @ 2011-06-13 11:57 UTC (permalink / raw)
To: Tanya Brokhman
Cc: 'open list:FREESCALE USB PER...', greg, linux-usb,
'open list', balbi, linux-arm-msm,
'open list:OMAP USB SUPPORT', ablay
In-Reply-To: <03b901cc29c0$6538e970$2faabc50$@org>
[-- Attachment #1: Type: text/plain, Size: 897 bytes --]
Hi,
On Mon, Jun 13, 2011 at 02:52:34PM +0300, Tanya Brokhman wrote:
> > On Sun, Jun 12, 2011 at 02:14:46PM +0300, Tatyana Brokhman wrote:
> > > Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
> >
> > I need a sensible commit log for this. Why do we need to change all
> > min() to min_t() ?
> >
>
> Actually, Alan asked me to make this change in one place in dummy_hcd. I
> wasn't aware of the min_t macro before that. So when I searched the code for
> other places I found quite a few and just thought that it would be "nicer"
> to use min_t() instead of min() with casting.
> So we don't "need" to make this change. Everything works as is. This patch
> only makes the code look nicer, nothing more.
> I can elaborate the above in the commit log if you want.
Yes, that's what I need. The question was supposed to be answered by the
commit log ;-)
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* RE: [PATCH] usb:gadget: use min_t() macro instead of min()
From: Tanya Brokhman @ 2011-06-13 11:52 UTC (permalink / raw)
To: balbi
Cc: ablay, greg, linux-usb, 'open list', linux-arm-msm,
'open list:OMAP USB SUPPORT',
'open list:FREESCALE USB PER...'
In-Reply-To: <20110613092438.GK3633@legolas.emea.dhcp.ti.com>
>
> On Sun, Jun 12, 2011 at 02:14:46PM +0300, Tatyana Brokhman wrote:
> > Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
>
> I need a sensible commit log for this. Why do we need to change all
> min() to min_t() ?
>
Actually, Alan asked me to make this change in one place in dummy_hcd. I
wasn't aware of the min_t macro before that. So when I searched the code for
other places I found quite a few and just thought that it would be "nicer"
to use min_t() instead of min() with casting.
So we don't "need" to make this change. Everything works as is. This patch
only makes the code look nicer, nothing more.
I can elaborate the above in the commit log if you want.
Thanks,
Tanya Brokhman
---
Sent by an consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply
* Re: [PATCH] usb:gadget: use min_t() macro instead of min()
From: Felipe Balbi @ 2011-06-13 9:24 UTC (permalink / raw)
To: Tatyana Brokhman
Cc: open list:FREESCALE USB PER..., greg, linux-usb, open list, balbi,
linux-arm-msm, open list:OMAP USB SUPPORT, ablay
In-Reply-To: <1307877290-26672-1-git-send-email-tlinder@codeaurora.org>
[-- Attachment #1: Type: text/plain, Size: 241 bytes --]
Hi,
On Sun, Jun 12, 2011 at 02:14:46PM +0300, Tatyana Brokhman wrote:
> Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
I need a sensible commit log for this. Why do we need to change all
min() to min_t() ?
--
balbi
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 490 bytes --]
^ permalink raw reply
* [PATCH] powerpc/85xx: fix NAND_CMD_READID read bytes number
From: Shaohui Xie @ 2011-06-13 2:23 UTC (permalink / raw)
To: linuxppc-dev; +Cc: scottwood, linux-mtd, Shaohui Xie
when nand_get_flash_type() is called, it will read 8 bytes of ID instead of 5,
but the driver only read 5 bytes, so kernel will dump error messages like:
fsl-lbc ffe124000.localbus: read_byte beyond end of buffer
fsl-lbc ffe124000.localbus: read_byte beyond end of buffer
fsl-lbc ffe124000.localbus: read_byte beyond end of buffer
Signed-off-by: Shaohui Xie <Shaohui.Xie@freescale.com>
Acked-by: Scott Wood <scottwood@freescale.com>
---
drivers/mtd/nand/fsl_elbc_nand.c | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/mtd/nand/fsl_elbc_nand.c b/drivers/mtd/nand/fsl_elbc_nand.c
index 0bb254c..33d8aad 100644
--- a/drivers/mtd/nand/fsl_elbc_nand.c
+++ b/drivers/mtd/nand/fsl_elbc_nand.c
@@ -339,9 +339,9 @@ static void fsl_elbc_cmdfunc(struct mtd_info *mtd, unsigned int command,
(FIR_OP_UA << FIR_OP1_SHIFT) |
(FIR_OP_RBW << FIR_OP2_SHIFT));
out_be32(&lbc->fcr, NAND_CMD_READID << FCR_CMD0_SHIFT);
- /* 5 bytes for manuf, device and exts */
- out_be32(&lbc->fbcr, 5);
- elbc_fcm_ctrl->read_bytes = 5;
+ /* nand_get_flash_type() reads 8 bytes of entire ID string */
+ out_be32(&lbc->fbcr, 8);
+ elbc_fcm_ctrl->read_bytes = 8;
elbc_fcm_ctrl->use_mdr = 1;
elbc_fcm_ctrl->mdr = 0;
--
1.6.4
^ permalink raw reply related
* [PATCH] slub: fix kernel BUG at mm/slub.c:1950!
From: Hugh Dickins @ 2011-06-13 2:03 UTC (permalink / raw)
To: Christoph Lameter; +Cc: linux-mm, Pekka Enberg, linuxppc-dev, linux-kernel
3.0-rc won't boot with SLUB on my PowerPC G5: kernel BUG at mm/slub.c:1950!
Bisected to 1759415e630e "slub: Remove CONFIG_CMPXCHG_LOCAL ifdeffery".
After giving myself a medal for finding the BUG on line 1950 of mm/slub.c
(it's actually the
VM_BUG_ON((unsigned long)(&pcp1) % (2 * sizeof(pcp1)));
on line 268 of the morass that is include/linux/percpu.h)
I tried the following alignment patch and found it to work.
Signed-off-by: Hugh Dickins <hughd@google.com>
---
include/linux/slub_def.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- 3.0-rc2/include/linux/slub_def.h 2011-05-29 18:42:37.077880848 -0700
+++ linux/include/linux/slub_def.h 2011-06-12 17:17:51.000000000 -0700
@@ -43,7 +43,7 @@ struct kmem_cache_cpu {
#ifdef CONFIG_SLUB_STATS
unsigned stat[NR_SLUB_STAT_ITEMS];
#endif
-};
+} __attribute__((aligned(2 * sizeof(long))));
struct kmem_cache_node {
spinlock_t list_lock; /* Protect partial list and nr_partial */
^ permalink raw reply
* [PATCH] usb:gadget: use min_t() macro instead of min()
From: Tatyana Brokhman @ 2011-06-12 11:14 UTC (permalink / raw)
To: greg
Cc: open list:FREESCALE USB PER..., Tatyana Brokhman, linux-arm-msm,
linux-usb, open list, balbi, open list:OMAP USB SUPPORT, ablay
Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
---
drivers/usb/gadget/composite.c | 16 ++++++++--------
drivers/usb/gadget/dummy_hcd.c | 2 +-
drivers/usb/gadget/f_fs.c | 6 +++---
drivers/usb/gadget/f_mass_storage.c | 20 ++++++++++----------
drivers/usb/gadget/file_storage.c | 22 +++++++++++-----------
drivers/usb/gadget/fsl_udc_core.c | 4 ++--
drivers/usb/gadget/gmidi.c | 10 +++++-----
drivers/usb/gadget/inode.c | 12 ++++++------
drivers/usb/gadget/mv_udc_core.c | 4 ++--
drivers/usb/gadget/omap_udc.c | 6 +++---
drivers/usb/gadget/printer.c | 16 ++++++++--------
drivers/usb/gadget/usbstring.c | 2 +-
drivers/usb/gadget/uvc_video.c | 4 ++--
13 files changed, 62 insertions(+), 62 deletions(-)
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index d825dbc..aa2db3f 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1085,7 +1085,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
cdev->desc.bcdUSB = cpu_to_le16(0x0210);
}
- value = min(w_length, (u16) sizeof cdev->desc);
+ value = min_t(u16, w_length, sizeof(cdev->desc));
memcpy(req->buf, &cdev->desc, value);
break;
case USB_DT_DEVICE_QUALIFIER:
@@ -1104,18 +1104,18 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
case USB_DT_CONFIG:
value = config_desc(cdev, w_value);
if (value >= 0)
- value = min(w_length, (u16) value);
+ value = min_t(u16, w_length, value);
break;
case USB_DT_STRING:
value = get_string(cdev, req->buf,
w_index, w_value & 0xff);
if (value >= 0)
- value = min(w_length, (u16) value);
+ value = min_t(u16, w_length, value);
break;
case USB_DT_BOS:
if (gadget_is_superspeed(gadget)) {
value = bos_desc(cdev);
- value = min(w_length, (u16) value);
+ value = min_t(u16, w_length, value);
}
break;
}
@@ -1144,7 +1144,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
*(u8 *)req->buf = cdev->config->bConfigurationValue;
else
*(u8 *)req->buf = 0;
- value = min(w_length, (u16) 1);
+ value = min_t(u16, w_length, 1);
break;
/* function drivers must handle get/set altsetting; if there's
@@ -1183,7 +1183,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (value < 0)
break;
*((u8 *)req->buf) = value;
- value = min(w_length, (u16) 1);
+ value = min_t(u16, w_length, 1);
break;
/*
@@ -1607,8 +1607,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,
driver->iProduct = driver->name;
composite_driver.function = (char *) driver->name;
composite_driver.driver.name = driver->name;
- composite_driver.speed = min((u8)composite_driver.speed,
- (u8)driver->max_speed);
+ composite_driver.speed = min_t(u8, composite_driver.speed,
+ driver->max_speed);
composite = driver;
composite_gadget_bind = bind;
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 74b7655..e134ea8 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -1213,7 +1213,7 @@ top:
/* not enough bandwidth left? */
if (limit < ep->ep.maxpacket && limit < len)
break;
- len = min (len, (unsigned) limit);
+ len = min_t(unsigned, len, limit);
if (len == 0)
break;
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index c161a9a..468e935 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -502,7 +502,7 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf,
}
/* FFS_SETUP_PENDING and not stall */
- len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+ len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
spin_unlock_irq(&ffs->ev.waitq.lock);
@@ -636,7 +636,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
}
return __ffs_ep0_read_events(ffs, buf,
- min(n, (size_t)ffs->ev.count));
+ min_t(size_t, n, ffs->ev.count));
case FFS_SETUP_PENDING:
if (ffs->ev.setup.bRequestType & USB_DIR_IN) {
@@ -645,7 +645,7 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
goto done_mutex;
}
- len = min(len, (size_t)le16_to_cpu(ffs->ev.setup.wLength));
+ len = min_t(size_t, len, le16_to_cpu(ffs->ev.setup.wLength));
spin_unlock_irq(&ffs->ev.waitq.lock);
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 5b93395..d7b3f9f 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -646,7 +646,7 @@ static int fsg_setup(struct usb_function *f,
*(u8 *)req->buf = fsg->common->nluns - 1;
/* Respond with data/status */
- req->length = min((u16)1, w_length);
+ req->length = min_t(u16, 1, w_length);
return ep0_queue(fsg->common);
}
@@ -790,11 +790,11 @@ static int do_read(struct fsg_common *common)
* the end of file.
*/
amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t)amount,
+ amount = min_t(loff_t, amount,
curlun->file_length - file_offset);
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0)
- amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
+ amount = min_t(unsigned int, amount, PAGE_CACHE_SIZE -
partial_page);
/* Wait for the next buffer to become available */
@@ -943,12 +943,12 @@ static int do_write(struct fsg_common *common)
* Finally, round down to a block boundary.
*/
amount = min(amount_left_to_req, FSG_BUFLEN);
- amount = min((loff_t)amount,
+ amount = min_t(loff_t, amount,
curlun->file_length - usb_offset);
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0)
- amount = min(amount,
- (unsigned int)PAGE_CACHE_SIZE - partial_page);
+ amount = min_t(unsigned int, amount,
+ PAGE_CACHE_SIZE - partial_page);
if (amount == 0) {
get_some_more = 0;
@@ -1152,7 +1152,7 @@ static int do_verify(struct fsg_common *common)
* past the end of file.
*/
amount = min(amount_left, FSG_BUFLEN);
- amount = min((loff_t)amount,
+ amount = min_t(loff_t, amount,
curlun->file_length - file_offset);
if (amount == 0) {
curlun->sense_data =
@@ -2203,7 +2203,7 @@ unknown_cmnd:
if (reply == -EINVAL)
reply = 0; /* Error reply length */
if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) {
- reply = min((u32)reply, common->data_size_from_cmnd);
+ reply = min_t(u32, reply, common->data_size_from_cmnd);
bh->inreq->length = reply;
bh->state = BUF_STATE_FULL;
common->residue -= reply;
@@ -3129,8 +3129,8 @@ fsg_config_from_params(struct fsg_config *cfg,
/* Configure LUNs */
cfg->nluns =
- min(params->luns ?: (params->file_count ?: 1u),
- (unsigned)FSG_MAX_LUNS);
+ min_t(unsigned, params->luns ?: (params->file_count ?: 1u),
+ FSG_MAX_LUNS);
for (i = 0, lun = cfg->luns; i < cfg->nluns; ++i, ++lun) {
lun->ro = !!params->ro[i];
lun->cdrom = !!params->cdrom[i];
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 0d55dee..aa8144d 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -1169,12 +1169,12 @@ static int do_read(struct fsg_dev *fsg)
* the next page.
* If this means reading 0 then we were asked to read past
* the end of file. */
- amount = min((unsigned int) amount_left, mod_data.buflen);
- amount = min((loff_t) amount,
+ amount = min_t(unsigned int, amount_left, mod_data.buflen);
+ amount = min_t(loff_t, amount,
curlun->file_length - file_offset);
partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0)
- amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
+ amount = min_t(unsigned int, amount, PAGE_CACHE_SIZE -
partial_page);
/* Wait for the next buffer to become available */
@@ -1316,12 +1316,12 @@ static int do_write(struct fsg_dev *fsg)
* to write past the end of file.
* Finally, round down to a block boundary. */
amount = min(amount_left_to_req, mod_data.buflen);
- amount = min((loff_t) amount, curlun->file_length -
+ amount = min_t(loff_t, amount, curlun->file_length -
usb_offset);
partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
if (partial_page > 0)
- amount = min(amount,
- (unsigned int) PAGE_CACHE_SIZE - partial_page);
+ amount = min_t(unsigned int, amount,
+ PAGE_CACHE_SIZE - partial_page);
if (amount == 0) {
get_some_more = 0;
@@ -1515,8 +1515,8 @@ static int do_verify(struct fsg_dev *fsg)
* And don't try to read past the end of the file.
* If this means reading 0 then we were asked to read
* past the end of file. */
- amount = min((unsigned int) amount_left, mod_data.buflen);
- amount = min((loff_t) amount,
+ amount = min_t(unsigned int, amount_left, mod_data.buflen);
+ amount = min_t(loff_t, amount,
curlun->file_length - file_offset);
if (amount == 0) {
curlun->sense_data =
@@ -1974,8 +1974,8 @@ static int throw_away_data(struct fsg_dev *fsg)
/* Try to submit another request if we need one */
bh = fsg->next_buffhd_to_fill;
if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) {
- amount = min(fsg->usb_amount_left,
- (u32) mod_data.buflen);
+ amount = min_t(u32, fsg->usb_amount_left,
+ mod_data.buflen);
/* amount is always divisible by 512, hence by
* the bulk-out maxpacket size */
@@ -2568,7 +2568,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
if (reply == -EINVAL)
reply = 0; // Error reply length
if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) {
- reply = min((u32) reply, fsg->data_size_from_cmnd);
+ reply = min_t(u32, reply, fsg->data_size_from_cmnd);
bh->inreq->length = reply;
bh->state = BUF_STATE_FULL;
fsg->residue -= reply;
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index 2cd9a60..5df6a1c 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -761,8 +761,8 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
struct ep_td_struct *dtd;
/* how big will this transfer be? */
- *length = min(req->req.length - req->req.actual,
- (unsigned)EP_MAX_LENGTH_TRANSFER);
+ *length = min_t(unsigned, req->req.length - req->req.actual,
+ EP_MAX_LENGTH_TRANSFER);
dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma);
if (dtd == NULL)
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index 4f40f14..9dab7a9 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -695,7 +695,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
switch (w_value >> 8) {
case USB_DT_DEVICE:
- value = min(w_length, (u16) sizeof(device_desc));
+ value = min_t(u16, w_length, sizeof(device_desc));
memcpy(req->buf, &device_desc, value);
break;
case USB_DT_CONFIG:
@@ -703,7 +703,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
w_value >> 8,
w_value & 0xff);
if (value >= 0) {
- value = min(w_length, (u16)value);
+ value = min_t(u16, w_length, value);
}
break;
@@ -716,7 +716,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
value = usb_gadget_get_string(&stringtab,
w_value & 0xff, req->buf);
if (value >= 0) {
- value = min(w_length, (u16)value);
+ value = min_t(u16, w_length, value);
}
break;
}
@@ -743,7 +743,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
goto unknown;
}
*(u8 *)req->buf = dev->config;
- value = min(w_length, (u16)1);
+ value = min_t(u16, w_length, 1);
break;
/* until we add altsetting support, or other interfaces,
@@ -785,7 +785,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
break;
}
*(u8 *)req->buf = 0;
- value = min(w_length, (u16)1);
+ value = min_t(u16, w_length, 1);
break;
default:
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index a9a4556..0a8c719 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -564,7 +564,7 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
len = 0;
to_copy = priv->buf;
for (i=0; i < priv->nr_segs; i++) {
- ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+ ssize_t this = min_t(ssize_t, priv->iv[i].iov_len, total);
if (copy_to_user(priv->iv[i].iov_base, to_copy, this)) {
if (len == 0)
@@ -1048,7 +1048,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
if (dev->setup_out_error)
retval = -EIO;
else {
- len = min (len, (size_t)dev->req->actual);
+ len = min_t(size_t, len, dev->req->actual);
// FIXME don't call this with the spinlock held ...
if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
@@ -1431,14 +1431,14 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
switch (w_value >> 8) {
case USB_DT_DEVICE:
- value = min (w_length, (u16) sizeof *dev->dev);
+ value = min_t(u16, w_length, sizeof(*dev->dev));
req->buf = dev->dev;
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!dev->hs_config)
break;
- value = min (w_length, (u16)
+ value = min_t(u16, w_length,
sizeof (struct usb_qualifier_descriptor));
make_qualifier (dev);
break;
@@ -1450,7 +1450,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
w_value >> 8,
w_value & 0xff);
if (value >= 0)
- value = min (w_length, (u16) value);
+ value = min_t(u16, w_length, value);
break;
case USB_DT_STRING:
goto unrecognized;
@@ -1512,7 +1512,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (ctrl->bRequestType != 0x80)
goto unrecognized;
*(u8 *)req->buf = dev->current_config;
- value = min (w_length, (u16) 1);
+ value = min_t(u16, w_length, 1);
break;
#endif
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index b1a8146..30d0b48 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -387,8 +387,8 @@ static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
struct mv_udc *udc;
/* how big will this transfer be? */
- *length = min(req->req.length - req->req.actual,
- (unsigned)EP_MAX_LENGTH_TRANSFER);
+ *length = min_t(unsigned, req->req.length - req->req.actual,
+ EP_MAX_LENGTH_TRANSFER);
udc = req->ep->udc;
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 82fd249..1183b7a 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -558,8 +558,8 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
length, 1, sync_mode, dma_trigger, 0);
} else {
- length = min(length / ep->maxpacket,
- (unsigned) UDC_TXN_TSC + 1);
+ length = min_t(unsigned, length / ep->maxpacket,
+ UDC_TXN_TSC + 1);
txdma_ctrl = length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, length, sync_mode,
@@ -626,7 +626,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
} else {
/* set up this DMA transfer, enable the fifo, start */
packets /= ep->ep.maxpacket;
- packets = min(packets, (unsigned)UDC_RXN_TC + 1);
+ packets = min_t(unsigned, packets, UDC_RXN_TC + 1);
req->dma_bytes = packets * ep->ep.maxpacket;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
ep->ep.maxpacket >> 1, packets,
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 00e5f19..f30bc7d 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -1148,15 +1148,15 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
switch (wValue >> 8) {
case USB_DT_DEVICE:
- value = min(wLength, (u16) sizeof device_desc);
+ value = min_t(u16, wLength, sizeof device_desc);
memcpy(req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
case USB_DT_DEVICE_QUALIFIER:
if (!gadget->is_dualspeed)
break;
- value = min(wLength,
- (u16) sizeof dev_qualifier);
+ value = min_t(u16, wLength,
+ sizeof(dev_qualifier));
memcpy(req->buf, &dev_qualifier, value);
break;
@@ -1171,14 +1171,14 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
wValue & 0xff,
gadget->is_otg);
if (value >= 0)
- value = min(wLength, (u16) value);
+ value = min_t(u16, wLength, value);
break;
case USB_DT_STRING:
value = usb_gadget_get_string(&stringtab,
wValue & 0xff, req->buf);
if (value >= 0)
- value = min(wLength, (u16) value);
+ value = min_t(u16, wLength, value);
break;
}
break;
@@ -1198,7 +1198,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
if (ctrl->bRequestType != USB_DIR_IN)
break;
*(u8 *)req->buf = dev->config;
- value = min(wLength, (u16) 1);
+ value = min_t(u16, wLength, 1);
break;
case USB_REQ_SET_INTERFACE:
@@ -1215,7 +1215,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
*(u8 *)req->buf = dev->interface;
- value = min(wLength, (u16) 1);
+ value = min_t(u16, wLength, 1);
break;
default:
@@ -1242,7 +1242,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
break;
*(u8 *)req->buf = dev->printer_status;
- value = min(wLength, (u16) 1);
+ value = min_t(u16, wLength, 1);
break;
case 2: /* Soft Reset */
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 58c4d37..f65916a 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -124,7 +124,7 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
return -EINVAL;
/* string descriptors have length, tag, then UTF16-LE text */
- len = min ((size_t) 126, strlen (s->s));
+ len = min_t(size_t, 126, strlen(s->s));
memset (buf + 2, 0, 2 * len); /* zero all the bytes */
len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
if (len < 0)
diff --git a/drivers/usb/gadget/uvc_video.c b/drivers/usb/gadget/uvc_video.c
index b08f354..0e3a34d 100644
--- a/drivers/usb/gadget/uvc_video.c
+++ b/drivers/usb/gadget/uvc_video.c
@@ -49,7 +49,7 @@ uvc_video_encode_data(struct uvc_video *video, struct uvc_buffer *buf,
/* Copy video data to the USB buffer. */
mem = queue->mem + buf->buf.m.offset + queue->buf_used;
- nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used);
+ nbytes = min_t(unsigned int, len, buf->buf.bytesused - queue->buf_used);
memcpy(data, mem, nbytes);
queue->buf_used += nbytes;
@@ -74,7 +74,7 @@ uvc_video_encode_bulk(struct usb_request *req, struct uvc_video *video,
}
/* Process video data. */
- len = min((int)(video->max_payload_size - video->payload_size), len);
+ len = min_t(int, video->max_payload_size - video->payload_size, len);
ret = uvc_video_encode_data(video, buf, mem, len);
video->payload_size += ret;
--
1.7.3.3
--
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.
^ permalink raw reply related
* Re: [PATCH 1/1] Big endian swap for Marvell 6440 SAS driver
From: Benjamin Herrenschmidt @ 2011-06-11 22:45 UTC (permalink / raw)
To: Cédric Cano; +Cc: linuxppc-dev, linux-scsi
In-Reply-To: <4DF2228E.7060806@ic.fr>
On Fri, 2011-06-10 at 15:56 +0200, Cédric Cano wrote:
> Hi,
>
> Marvell SAS driver doesn't work on powerpc architecture due to big
> endian swap. I've tested it with the MV6440 chip.
> Here you can find the patch for Linux 2.6.39.1.
>
> Cedric Cano
>
> Signed-off-by: Cedric Cano <ccano@interfaceconcept.com>
> ---
> --- drivers/scsi/mvsas/mv_sas.c 2011-06-10 15:50:04.000000000 +0200
> +++ drivers/scsi/mvsas/mv_sas.c 2011-06-10 15:50:12.000000000 +0200
> @@ -1143,6 +1143,14 @@
> MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
> s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
>
> + /* swap for big endian devices because of use of these data in bytes */
> +#ifdef __BIG_ENDIAN
> + s[0] = swab32(s[0]);
> + s[1] = swab32(s[1]);
> + s[2] = swab32(s[2]);
> + s[3] = swab32(s[3]);
> +#endif /* __BIG_ENDIAN */
Hi Cedric !
Thanks for this. CC'ing linux-scsi.
Note that it would probably have been better to use le32_to_cpu, which
avoids the ifdef completely.
Cheers,
Ben.
> /* Workaround: take some ATAPI devices for ATA */
> if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
> s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
>
> ---
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* [PATCH 2/2] powerpc: Add printk companion for ppc_md.progress
From: Dave Carroll @ 2011-06-11 1:38 UTC (permalink / raw)
To: Milton Miller, BenH; +Cc: Dave Carroll, LPPC, LKML
In-Reply-To: <1307756291-26513-1-git-send-email-dcarroll@astekcorp.com>
From: Dave Carroll <dcarroll@astekcorp.com>
This patch adds a printk companion to replace the udbg progress function
when initmem is freed.
Suggested-by: Milton Miller <miltonm@bga.com>
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Dave Carroll <dcarroll@astekcorp.com>
---
arch/powerpc/include/asm/setup.h | 2 ++
arch/powerpc/kernel/setup-common.c | 5 +++++
arch/powerpc/mm/mem.c | 2 +-
3 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/arch/powerpc/include/asm/setup.h b/arch/powerpc/include/asm/setup.h
index dae1934..c77cb7a 100644
--- a/arch/powerpc/include/asm/setup.h
+++ b/arch/powerpc/include/asm/setup.h
@@ -3,4 +3,6 @@
#include <asm-generic/setup.h>
+extern void ppc_printk_progress(char *s, unsigned short hex);
+
#endif /* _ASM_POWERPC_SETUP_H */
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 79fca26..e053b16 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -704,6 +704,11 @@ static int powerpc_debugfs_init(void)
arch_initcall(powerpc_debugfs_init);
#endif
+void ppc_printk_progress(char *s, unsigned short hex)
+{
+ pr_info("%s\n", s);
+}
+
static int ppc_dflt_bus_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index f4e6408..e0d2aa0 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -386,7 +386,7 @@ void free_initmem(void)
{
unsigned long addr;
- ppc_md.progress = NULL;
+ ppc_md.progress = ppc_printk_progress;
addr = (unsigned long)__init_begin;
for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
--
1.7.4
^ permalink raw reply related
* [PATCH 1/2] powerpc: Move free_initmem to common code
From: Dave Carroll @ 2011-06-11 1:38 UTC (permalink / raw)
To: Milton Miller, BenH; +Cc: Dave Carroll, LPPC, LKML
In-Reply-To: <initrd-align-v5-reply@mdm.bga.com>
From: Dave Carroll <dcarroll@astekcorp.com>
The free_initmem function is basically duplicated in mm/init_32,
and init_64, and is moved to the common 32/64-bit mm/mem.c.
All other sections except init were removed in v2.6.15 by
6c45ab992e4299c869fb26427944a8f8ea177024 (powerpc: Remove section
free() and linker script bits), and therefore the bulk of the executed
code is identical.
This patch also removes updating ppc_md.progress to NULL in the powermac
late_initcall.
Suggested-by: Milton Miller <miltonm@bga.com>
Suggested-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Dave Carroll <dcarroll@astekcorp.com>
---
arch/powerpc/mm/init_32.c | 32 -------------------------------
arch/powerpc/mm/init_64.c | 16 ---------------
arch/powerpc/mm/mem.c | 19 ++++++++++++++++++
arch/powerpc/platforms/powermac/setup.c | 3 --
4 files changed, 19 insertions(+), 51 deletions(-)
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c
index 5de0f25..c77fef5 100644
--- a/arch/powerpc/mm/init_32.c
+++ b/arch/powerpc/mm/init_32.c
@@ -191,38 +191,6 @@ void __init *early_get_page(void)
return __va(memblock_alloc(PAGE_SIZE, PAGE_SIZE));
}
-/* Free up now-unused memory */
-static void free_sec(unsigned long start, unsigned long end, const char *name)
-{
- unsigned long cnt = 0;
-
- while (start < end) {
- ClearPageReserved(virt_to_page(start));
- init_page_count(virt_to_page(start));
- free_page(start);
- cnt++;
- start += PAGE_SIZE;
- }
- if (cnt) {
- printk(" %ldk %s", cnt << (PAGE_SHIFT - 10), name);
- totalram_pages += cnt;
- }
-}
-
-void free_initmem(void)
-{
-#define FREESEC(TYPE) \
- free_sec((unsigned long)(&__ ## TYPE ## _begin), \
- (unsigned long)(&__ ## TYPE ## _end), \
- #TYPE);
-
- printk ("Freeing unused kernel memory:");
- FREESEC(init);
- printk("\n");
- ppc_md.progress = NULL;
-#undef FREESEC
-}
-
#ifdef CONFIG_8xx /* No 8xx specific .c file to put that in ... */
void setup_initial_memory_limit(phys_addr_t first_memblock_base,
phys_addr_t first_memblock_size)
diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c
index f6dbb4c..e94b57f 100644
--- a/arch/powerpc/mm/init_64.c
+++ b/arch/powerpc/mm/init_64.c
@@ -83,22 +83,6 @@ EXPORT_SYMBOL_GPL(memstart_addr);
phys_addr_t kernstart_addr;
EXPORT_SYMBOL_GPL(kernstart_addr);
-void free_initmem(void)
-{
- unsigned long addr;
-
- addr = (unsigned long)__init_begin;
- for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
- memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
- ClearPageReserved(virt_to_page(addr));
- init_page_count(virt_to_page(addr));
- free_page(addr);
- totalram_pages++;
- }
- printk ("Freeing unused kernel memory: %luk freed\n",
- ((unsigned long)__init_end - (unsigned long)__init_begin) >> 10);
-}
-
static void pgd_ctor(void *addr)
{
memset(addr, 0, PGD_TABLE_SIZE);
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 29d4dde..f4e6408 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -382,6 +382,25 @@ void __init mem_init(void)
mem_init_done = 1;
}
+void free_initmem(void)
+{
+ unsigned long addr;
+
+ ppc_md.progress = NULL;
+
+ addr = (unsigned long)__init_begin;
+ for (; addr < (unsigned long)__init_end; addr += PAGE_SIZE) {
+ memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE);
+ ClearPageReserved(virt_to_page(addr));
+ init_page_count(virt_to_page(addr));
+ free_page(addr);
+ totalram_pages++;
+ }
+ pr_info("Freeing unused kernel memory: %luk freed\n",
+ ((unsigned long)__init_end -
+ (unsigned long)__init_begin) >> 10);
+}
+
#ifdef CONFIG_BLK_DEV_INITRD
void __init free_initrd_mem(unsigned long start, unsigned long end)
{
diff --git a/arch/powerpc/platforms/powermac/setup.c b/arch/powerpc/platforms/powermac/setup.c
index aa45281..a028f08 100644
--- a/arch/powerpc/platforms/powermac/setup.c
+++ b/arch/powerpc/platforms/powermac/setup.c
@@ -355,9 +355,6 @@ static int initializing = 1;
static int pmac_late_init(void)
{
initializing = 0;
- /* this is udbg (which is __init) and we can later use it during
- * cpu hotplug (in smp_core99_kick_cpu) */
- ppc_md.progress = NULL;
return 0;
}
machine_late_initcall(powermac, pmac_late_init);
--
1.7.4
^ permalink raw reply related
* Re: 3.0-rc1: powerpc hangs at Kernel virtual memory layout
From: Rafał Miłecki @ 2011-06-10 22:59 UTC (permalink / raw)
To: Christian Kujau; +Cc: linux ppc dev, LKML
In-Reply-To: <alpine.DEB.2.01.1106101552460.9183@trent.utfs.org>
2011/6/11 Christian Kujau <lists@nerdbynature.de>:
> On Thu, 2 Jun 2011 at 12:57, Benjamin Herrenschmidt wrote:
>> John, care to send the patch below to Linus ASAP ? I could reproduce and
>> verify it fixes it. Thanks !
>>
>> ssb: pci: Don't call PCIe specific workarounds on PCI cores
>>
>> Otherwise it can/will crash....
>
> The patch did not make it into -rc2, it's not in today's git tree either,
> AFAICS. Can anyone push this, please?
Yeah, I noticed it wasn't in the pull for rc2. I pinged John, he told
me to just wait.
Patch was taken with the recent pull, it should go into rc3.
--=20
Rafa=C5=82
^ permalink raw reply
* Re: 3.0-rc1: powerpc hangs at Kernel virtual memory layout
From: Christian Kujau @ 2011-06-10 22:54 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: zajec5, linux ppc dev, LKML
In-Reply-To: <1306983467.29297.51.camel@pasglop>
On Thu, 2 Jun 2011 at 12:57, Benjamin Herrenschmidt wrote:
> John, care to send the patch below to Linus ASAP ? I could reproduce and
> verify it fixes it. Thanks !
>
> ssb: pci: Don't call PCIe specific workarounds on PCI cores
>
> Otherwise it can/will crash....
The patch did not make it into -rc2, it's not in today's git tree either,
AFAICS. Can anyone push this, please?
Thanks,
Christian.
> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> ---
>
> diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
> index 82feb34..eddf1b9 100644
> --- a/drivers/ssb/driver_pcicore.c
> +++ b/drivers/ssb/driver_pcicore.c
> @@ -540,7 +540,8 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)
> ssb_pcicore_init_clientmode(pc);
>
> /* Additional always once-executed workarounds */
> - ssb_pcicore_serdes_workaround(pc);
> + if (dev->id.coreid == SSB_DEV_PCIE)
> + ssb_pcicore_serdes_workaround(pc);
> /* TODO: ASPM */
> /* TODO: Clock Request Update */
> }
>
--
BOFH excuse #312:
incompatible bit-registration operators
^ permalink raw reply
* [PATCH 1/1] Big endian swap for Marvell 6440 SAS driver
From: Cédric Cano @ 2011-06-10 13:56 UTC (permalink / raw)
To: linuxppc-dev
Hi,
Marvell SAS driver doesn't work on powerpc architecture due to big
endian swap. I've tested it with the MV6440 chip.
Here you can find the patch for Linux 2.6.39.1.
Cedric Cano
Signed-off-by: Cedric Cano <ccano@interfaceconcept.com>
---
--- drivers/scsi/mvsas/mv_sas.c 2011-06-10 15:50:04.000000000 +0200
+++ drivers/scsi/mvsas/mv_sas.c 2011-06-10 15:50:12.000000000 +0200
@@ -1143,6 +1143,14 @@
MVS_CHIP_DISP->write_port_cfg_addr(mvi, i, PHYR_SATA_SIG0);
s[0] = MVS_CHIP_DISP->read_port_cfg_data(mvi, i);
+ /* swap for big endian devices because of use of these data in bytes */
+#ifdef __BIG_ENDIAN
+ s[0] = swab32(s[0]);
+ s[1] = swab32(s[1]);
+ s[2] = swab32(s[2]);
+ s[3] = swab32(s[3]);
+#endif /* __BIG_ENDIAN */
+
/* Workaround: take some ATAPI devices for ATA */
if (((s[1] & 0x00FFFFFF) == 0x00EB1401) && (*(u8 *)&s[3] == 0x01))
s[1] = 0x00EB1401 | (*((u8 *)&s[1] + 3) & 0x10);
---
^ permalink raw reply
* Re: [PATCH 7/7] [v4] drivers/virt: introduce Freescale hypervisor management driver
From: Arnd Bergmann @ 2011-06-10 15:36 UTC (permalink / raw)
To: Chris Metcalf
Cc: Randy Dunlap, konrad.wilk, greg, kumar.gala, linux-kernel,
Linux Virtualization, dsaxena, linux-console, akpm, linuxppc-dev,
Timur Tabi, alan
In-Reply-To: <4DF22770.4010103@tilera.com>
On Friday 10 June 2011, Chris Metcalf wrote:
> This still leaves open the question of what really should go in this new
> directory. Is it just for drivers that manage/control the hypervisor? Or
> is it also for drivers that just use the hypervisor to do I/O of some kind,
> but aren't related to any other "family" of drivers, i.e., a driver that
> would have been dumped in drivers/char or drivers/misc in the old days?
>
> My specific interest at the moment is the proposed tile-srom.c driver
> (https://patchwork.kernel.org/patch/843892/), which uses a simple
> hypervisor read/write API to access the portion of the SPI ROM used to hold
> the boot stream for a TILE processor.
I'd still put that driver in drivers/char for now, because it already contains
similar drivers. We can probaby group them in a subdirectory of drivers/char
at some point or move them out to a new directory.
For your raw hcall passthrough driver, that would be something that should
go into drivers/virt/ IMHO.
Arnd
^ permalink raw reply
* Re: [PATCH 7/7] [v4] drivers/virt: introduce Freescale hypervisor management driver
From: Chris Metcalf @ 2011-06-10 14:17 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Randy Dunlap, konrad.wilk, greg, kumar.gala, linux-kernel,
Linux Virtualization, dsaxena, linux-console, akpm, linuxppc-dev,
Timur Tabi, alan
In-Reply-To: <201106090938.23027.arnd@arndb.de>
On 6/9/2011 3:38 AM, Arnd Bergmann wrote:
> On Thursday 09 June 2011 01:10:09 Randy Dunlap wrote:
>> On Wed, 8 Jun 2011 17:45:54 -0500 Timur Tabi wrote:
>>
>>> Add the drivers/virt directory, which houses drivers that support
>>> virtualization environments, and add the Freescale hypervisor management
>>> driver.
>> It can't go in linux/virt or linux/virt/fsl instead? why drivers/ ?
>>
>> or maybe linux/virt should be drivers/virt ?
> See discussion for v2 of this patch. I suggested that drivers/firmware and virt/
> as options, the counterarguments were that drivers/firmware is for passive
> firmware as opposed to firmware that acts as a hypervisor, and that virt/ is
> for the host side of hypervisors like kvm, not for guests.
>
> The driver in here most closely resembles the xen dom0 model, where a
> priviledged guest controls other guests, but unlike xen there is a single
> driver file, so there is no need to have drivers/fsl-hv directory just
> for this one file. We do have a number of other hypervisors that fit in the
> same category, so they can be added here later.
This still leaves open the question of what really should go in this new
directory. Is it just for drivers that manage/control the hypervisor? Or
is it also for drivers that just use the hypervisor to do I/O of some kind,
but aren't related to any other "family" of drivers, i.e., a driver that
would have been dumped in drivers/char or drivers/misc in the old days?
My specific interest at the moment is the proposed tile-srom.c driver
(https://patchwork.kernel.org/patch/843892/), which uses a simple
hypervisor read/write API to access the portion of the SPI ROM used to hold
the boot stream for a TILE processor.
--
Chris Metcalf, Tilera Corp.
http://www.tilera.com
^ permalink raw reply
* [PATCH] ppc, exec: remove redundant set_fs(USER_DS)
From: Mathias Krause @ 2011-06-10 13:10 UTC (permalink / raw)
To: Benjamin Herrenschmidt
Cc: linuxppc-dev, Andrew Morton, Linus Torvalds, linux-kernel,
Mathias Krause
In-Reply-To: <BANLkTinv1teZEHMK0qymaVdcxPOErpqSyg@mail.gmail.com>
The address limit is already set in flush_old_exec() so this
set_fs(USER_DS) is redundant.
Signed-off-by: Mathias Krause <minipli@googlemail.com>
---
arch/powerpc/kernel/process.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index 91e52df..885a2dd 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -831,8 +831,6 @@ void start_thread(struct pt_regs *regs, unsigned long start, unsigned long sp)
unsigned long load_addr = regs->gpr[2]; /* saved by ELF_PLAT_INIT */
#endif
- set_fs(USER_DS);
-
/*
* If we exec out of a kernel thread then thread.regs will not be
* set. Do it now.
--
1.5.6.5
^ permalink raw reply related
* Re: [PATCH 7/7] [v5] drivers/virt: introduce Freescale hypervisor management driver
From: Mark Brown @ 2011-06-10 10:45 UTC (permalink / raw)
To: Arnd Bergmann
Cc: konrad.wilk, kumar.gala, linux-kernel, cmetcalf, akpm,
linux-console, greg, virtualization, linuxppc-dev, Timur Tabi,
alan
In-Reply-To: <201106092233.08030.arnd@arndb.de>
On Thu, Jun 09, 2011 at 10:33:07PM +0200, Arnd Bergmann wrote:
> On Thursday 09 June 2011 22:18:28 Timur Tabi wrote:
> > Ok, I was really hoping to avoid doing this. Like I said, binary compatibility
> > is important, and changing the type will break my existing apps. Are you
> > insisting that I pick a new number?
> I definitely insist that you have a proper interface in the driver at the
> time that it gets merged, and that probably includes a collision-free
> ioctl code.
This sort of stuff is one of the issues that should be being factored in
to any decision not to publish and submit the kernel code - ABIs that
haven't been reviewed upstream may well have this sort of issue.
^ permalink raw reply
* RE: [PATCH 7/7] [v5] drivers/virt: introduce Freescale hypervisormanagement driver
From: David Laight @ 2011-06-10 8:32 UTC (permalink / raw)
To: Arnd Bergmann, Timur Tabi, linuxppc-dev
Cc: konrad.wilk, greg, kumar.gala, linux-kernel, cmetcalf, akpm,
linux-console, virtualization, alan
In-Reply-To: <201106092213.13755.arnd@arndb.de>
=20
> > +enum fsl_hv_ioctl_cmd {
> > + FSL_HV_IOCTL_PARTITION_RESTART =3D _IOWR(0, 1, struct
fsl_hv_ioctl_restart),
...
> > +};
>=20
> Using a #define here is usually preferred because then you=20
> can use #ifdef in a user application to check if a given
> value has been assigned.
It is also possible to add:
#define FSL_HV_IOCTL_PARTITION_RESTART FSL_HV_IOCTL_PARTITION_RESTART
to have much the same effect.
But there are many cases where #defines are better.
I only tend to use enums when the constanst are beting generated
by the expansion of a #define.
> More importantly, the code you have chose (0) conflicts with=20
> existing drivers (frame buffer, scsi and wavefront among others).
> Please chose a free one and
> add it to Documentation/ioctl/ioctl-number.txt in the same patch.
It is rather a PITA that, when 'int' went from 16 to 32 bits, the
BSD people used the high 16 bits for size/flags rather than
using the extra bits to help make ioctl's unique.
Linux seems to have copied BSD here - rather than SYSV.
One problem with clashing ioctl commands is when systems like
NetBSD are running linux binaries and need to translate ioctl
buffers to/from native format. If the ioctl commands are
unique this can be done much more easily.
David
^ permalink raw reply
* Re: [PATCH] [RFC][V3] bluegene: use MMU feature flag to conditionalize L1 writethrough code
From: Eric Van Hensbergen @ 2011-06-10 3:23 UTC (permalink / raw)
To: Benjamin Herrenschmidt; +Cc: linuxppc-dev, linux-kernel, bg-linux
In-Reply-To: <1307662948.2874.293.camel@pasglop>
On Thu, Jun 9, 2011 at 6:42 PM, Benjamin Herrenschmidt
<benh@kernel.crashing.org> wrote:
> On Thu, 2011-06-09 at 09:58 -0500, Eric Van Hensbergen wrote:
>> On Tue, Jun 7, 2011 at 7:47 PM, Benjamin Herrenschmidt
>> <benh@kernel.crashing.org> wrote:
>> > BTW. Care to explain to me why you have U2 -both- in the arguments to
>> > tlbwe and in MMUCR ? That doesn't look right to me... which one is used
>> > where and when ?
>> >
>>
>> My reading of the databook is that U2SWOAE is an enable bit that lets the U2
>> storage attribute control the behavior.
>
> You mean the MMUCR variant ?
>
Yeah, the MMCR variant acts as an enable/mask for the U2 storage attribute.
>
> Well, point is, parsing the device-tree from early boot asm is nasty,
> unless you start extending the header but that sucks. That's why I'm
> thinking it might be a good idea to look at what it takes to "convert"
> the initial entry instead, even if that involves some cache flushing
> (provided that's workable at all of course).
>
ah, okay. I guess if its happening before the secondary cpus come up
then that should be workable. I guess it doesn't hurt to try.
-eric
^ permalink raw reply
* Re: [PATCH] [RFC][V3] bluegene: use MMU feature flag to conditionalize L1 writethrough code
From: Benjamin Herrenschmidt @ 2011-06-09 23:42 UTC (permalink / raw)
To: Eric Van Hensbergen; +Cc: linuxppc-dev, linux-kernel, bg-linux
In-Reply-To: <BANLkTinD+1+QTUhKvQP-T_bZgbi1YS1jwQ@mail.gmail.com>
On Thu, 2011-06-09 at 09:58 -0500, Eric Van Hensbergen wrote:
> On Tue, Jun 7, 2011 at 7:47 PM, Benjamin Herrenschmidt
> <benh@kernel.crashing.org> wrote:
> > On Tue, 2011-06-07 at 16:36 -0500, Eric Van Hensbergen wrote:
> >
> >> open to alternatives. jimix also suggested changing NEED_L1_WRITETHROUGH
> >> to DCBZ_BROKEN, which I'm open to if you think appropriate, or maybe
> >> DCBZ_BROKEN_DAMNIT would be more apt.
> >
> > :-)
> >
> > I think NEED_L1_WRITETHROUGH isn't great since we are dealing with more
> > than just that here. Let's call it 44x_SMP since afaik, all
> > implementations, whether it's BG or other variants of the same hack
> > (AMCC/APM has one too) need the same stuff here, no ?
> >
> > Let's not use more than one feature bit, it's not needed in practice, a
> > better name is all we need. Might even call it MMU_FTR_BLUEGENE_44x_SMP
> > if you want.
> >
>
> I've got it as MMU_FTR_44x_SMP now,
Keep it BGP for now as my understanding is that some of those TLB bits
are quite specific to the way the BGP ASIC operates. AFAIK The only
possible other user of that is that dual 464 chip from AMCC/APM but I
yet have to see them try to get SMP on that, and I don't know how their
caches work at this point.
> just wanted to bounce off of Josh to
> make sure he's okay with it since he owns the 44x stuff. If he'd
> rather, I'll change
> it to MMU_FTR_BGP_44x_SMP.
>
> >
> > I'll add comments inline:
> >
> >> #define PPC44x_MMUCR_TID 0x000000ff
> >> #define PPC44x_MMUCR_STS 0x00010000
> >> +#define PPC44x_MMUCR_U2 0x00200000
> >
> > Please document in a comment what is the effect of U2 on the BG/P ASIC
> > caches.
> >
>
> Is a comment sufficient, or would you rather also have something along
> the lines of
> +#define PPC44x_MMUCR_U2 0x00200000
> +#define PPC44x_MMUCR_U2_SWOAE PPC44x_MMUCR_U2 /* store without allocation */
>
> or even...
> +#define PPC44x_MMUCR_U2_BGP_SWOAE PPC44x_MMUCR_U2 /* store without
> allocation on BGP */
My point was more like: You have U2, that other W1 bit etc... it's
unclear which does what here and a blurb explaining how the caches
operate on this setup would be useful.
I don't care much about the name of the constants, "SWOAE" isn't very
informative either, I'm really talking about adding a nice comment
explaining what they do :-)
> Seems like its getting a bit too verbose, maybe that's not a bad
> thing. As long as I don't have to type it
> too many times :)
Right, don't make the constant horrible, just explain what it does.
> > BTW. Care to explain to me why you have U2 -both- in the arguments to
> > tlbwe and in MMUCR ? That doesn't look right to me... which one is used
> > where and when ?
> >
>
> My reading of the databook is that U2SWOAE is an enable bit that lets the U2
> storage attribute control the behavior.
You mean the MMUCR variant ?
> >> @@ -814,7 +829,15 @@ skpinv: addi r4,r4,1 /* Increment */
> >> /* attrib fields */
> >> /* Added guarded bit to protect against speculative loads/stores */
> >> li r5,0
> >> - ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | PPC44x_TLB_G)
> >> +BEGIN_MMU_FTR_SECTION
> >> + ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | \
> >> + PPC44x_TLB_G | PPC44x_TLB_U2)
> >> + oris r5,r5,PPC44x_TLB_WL1@h
> >> +END_MMU_FTR_SECTION_IFSET(MMU_FTR_NEED_L1_WRITETHROUGH)
> >> +BEGIN_MMU_FTR_SECTION
> >> + ori r5,r5,(PPC44x_TLB_SW | PPC44x_TLB_SR | PPC44x_TLB_SX | \
> >> + PPC44x_TLB_G)
> >> +END_MMU_FTR_SECTION_IFCLR(MMU_FTR_NEED_L1_WRITETHROUGH)
> >>
> >> li r0,63 /* TLB slot 63 */
> >
> > This isn't going to work. This happens before the CPU feature bits are
> > established.
> >
> > I see two ways out of that dilemna:
> >
> > - One is you find a way to identify the BG case at runtime from that
> > very early asm code. It's a bit tricky since we never added the MMU type
> > information to the device-tree blob header (but we're adding it to ePAPR
> > via a register iirc, so we could hijack that), or maybe via inspecting
> > what the FW left behind in the TLB...
> >
>
> Well, if we are using the u-boot scenario, I can control how the
> bootloader sets up the device tree and add markers that we can use to
> let us do this.
Well, point is, parsing the device-tree from early boot asm is nasty,
unless you start extending the header but that sucks. That's why I'm
thinking it might be a good idea to look at what it takes to "convert"
the initial entry instead, even if that involves some cache flushing
(provided that's workable at all of course).
Cheers
Ben.
^ permalink raw reply
* Re: [PATCH 7/7] [v6] drivers/virt: introduce Freescale hypervisor management driver
From: Arnd Bergmann @ 2011-06-09 21:04 UTC (permalink / raw)
To: virtualization
Cc: konrad.wilk, kumar.gala, linux-kernel, cmetcalf, akpm, dsaxena,
linux-console, greg, linuxppc-dev, Timur Tabi, alan
In-Reply-To: <1307652726-4356-1-git-send-email-timur@freescale.com>
On Thursday 09 June 2011 22:52:06 Timur Tabi wrote:
> Add the drivers/virt directory, which houses drivers that support
> virtualization environments, and add the Freescale hypervisor management
> driver.
>
> The Freescale hypervisor management driver provides several services to
> drivers and applications related to the Freescale hypervisor:
>
> 1. An ioctl interface for querying and managing partitions
>
> 2. A file interface to reading incoming doorbells
>
> 3. An interrupt handler for shutting down the partition upon receiving the
> shutdown doorbell from a manager partition
>
> 4. A kernel interface for receiving callbacks when a managed partition
> shuts down.
>
> Signed-off-by: Timur Tabi <timur@freescale.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
* [PATCH 7/7] [v6] drivers/virt: introduce Freescale hypervisor management driver
From: Timur Tabi @ 2011-06-09 20:52 UTC (permalink / raw)
To: alan, arnd, kumar.gala, benh, greg, akpm, cmetcalf, konrad.wilk,
dsaxena, linuxppc-dev, linux-kernel, linux-console,
virtualization
Add the drivers/virt directory, which houses drivers that support
virtualization environments, and add the Freescale hypervisor management
driver.
The Freescale hypervisor management driver provides several services to
drivers and applications related to the Freescale hypervisor:
1. An ioctl interface for querying and managing partitions
2. A file interface to reading incoming doorbells
3. An interrupt handler for shutting down the partition upon receiving the
shutdown doorbell from a manager partition
4. A kernel interface for receiving callbacks when a managed partition
shuts down.
Signed-off-by: Timur Tabi <timur@freescale.com>
---
Documentation/ioctl/ioctl-number.txt | 1 +
drivers/Kconfig | 2 +
drivers/Makefile | 3 +
drivers/virt/Kconfig | 32 ++
drivers/virt/Makefile | 5 +
drivers/virt/fsl_hypervisor.c | 937 ++++++++++++++++++++++++++++++++++
include/linux/Kbuild | 1 +
include/linux/fsl_hypervisor.h | 241 +++++++++
8 files changed, 1222 insertions(+), 0 deletions(-)
create mode 100644 drivers/virt/Kconfig
create mode 100644 drivers/virt/Makefile
create mode 100644 drivers/virt/fsl_hypervisor.c
create mode 100644 include/linux/fsl_hypervisor.h
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index a0a5d82..9b8a8bd 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -301,6 +301,7 @@ Code Seq#(hex) Include File Comments
<mailto:rusty@rustcorp.com.au>
0xAE all linux/kvm.h Kernel-based Virtual Machine
<mailto:kvm@vger.kernel.org>
+0xAF 00-1F linux/fsl_hypervisor.h Freescale hypervisor
0xB0 all RATIO devices in development:
<mailto:vgo@ratio.de>
0xB1 00-1F PPPoX <mailto:mostrows@styx.uwaterloo.ca>
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 557a469..0371680 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -122,4 +122,6 @@ source "drivers/hwspinlock/Kconfig"
source "drivers/clocksource/Kconfig"
+source "drivers/virt/Kconfig"
+
endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index 3f135b6..bbe2918 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -119,3 +119,6 @@ obj-y += ieee802154/
obj-y += clk/
obj-$(CONFIG_HWSPINLOCK) += hwspinlock/
+
+# Virtualization drivers
+obj-$(CONFIG_VIRT_DRIVERS) += virt/
diff --git a/drivers/virt/Kconfig b/drivers/virt/Kconfig
new file mode 100644
index 0000000..2dcdbc9
--- /dev/null
+++ b/drivers/virt/Kconfig
@@ -0,0 +1,32 @@
+#
+# Virtualization support drivers
+#
+
+menuconfig VIRT_DRIVERS
+ bool "Virtualization drivers"
+ ---help---
+ Say Y here to get to see options for device drivers that support
+ virtualization environments.
+
+ If you say N, all options in this submenu will be skipped and disabled.
+
+if VIRT_DRIVERS
+
+config FSL_HV_MANAGER
+ tristate "Freescale hypervisor management driver"
+ depends on FSL_SOC
+ help
+ The Freescale hypervisor management driver provides several services
+ to drivers and applications related to the Freescale hypervisor:
+
+ 1) An ioctl interface for querying and managing partitions.
+
+ 2) A file interface to reading incoming doorbells.
+
+ 3) An interrupt handler for shutting down the partition upon
+ receiving the shutdown doorbell from a manager partition.
+
+ 4) A kernel interface for receiving callbacks when a managed
+ partition shuts down.
+
+endif
diff --git a/drivers/virt/Makefile b/drivers/virt/Makefile
new file mode 100644
index 0000000..c47f04d
--- /dev/null
+++ b/drivers/virt/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for drivers that support virtualization
+#
+
+obj-$(CONFIG_FSL_HV_MANAGER) += fsl_hypervisor.o
diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c
new file mode 100644
index 0000000..1d3b8eb
--- /dev/null
+++ b/drivers/virt/fsl_hypervisor.c
@@ -0,0 +1,937 @@
+/*
+ * Freescale Hypervisor Management Driver
+
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * The Freescale hypervisor management driver provides several services to
+ * drivers and applications related to the Freescale hypervisor:
+ *
+ * 1. An ioctl interface for querying and managing partitions.
+ *
+ * 2. A file interface to reading incoming doorbells.
+ *
+ * 3. An interrupt handler for shutting down the partition upon receiving the
+ * shutdown doorbell from a manager partition.
+ *
+ * 4. A kernel interface for receiving callbacks when a managed partition
+ * shuts down.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/of.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/notifier.h>
+
+#include <linux/io.h>
+#include <asm/fsl_hcalls.h>
+
+#include <linux/fsl_hypervisor.h>
+
+static BLOCKING_NOTIFIER_HEAD(failover_subscribers);
+
+/*
+ * Ioctl interface for FSL_HV_IOCTL_PARTITION_RESTART
+ *
+ * Restart a running partition
+ */
+static long ioctl_restart(struct fsl_hv_ioctl_restart __user *p)
+{
+ struct fsl_hv_ioctl_restart param;
+
+ /* Get the parameters from the user */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_restart)))
+ return -EFAULT;
+
+ param.ret = fh_partition_restart(param.partition);
+
+ if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Ioctl interface for FSL_HV_IOCTL_PARTITION_STATUS
+ *
+ * Query the status of a partition
+ */
+static long ioctl_status(struct fsl_hv_ioctl_status __user *p)
+{
+ struct fsl_hv_ioctl_status param;
+ u32 status;
+
+ /* Get the parameters from the user */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_status)))
+ return -EFAULT;
+
+ param.ret = fh_partition_get_status(param.partition, &status);
+ if (!param.ret)
+ param.status = status;
+
+ if (copy_to_user(p, ¶m, sizeof(struct fsl_hv_ioctl_status)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Ioctl interface for FSL_HV_IOCTL_PARTITION_START
+ *
+ * Start a stopped partition.
+ */
+static long ioctl_start(struct fsl_hv_ioctl_start __user *p)
+{
+ struct fsl_hv_ioctl_start param;
+
+ /* Get the parameters from the user */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_start)))
+ return -EFAULT;
+
+ param.ret = fh_partition_start(param.partition, param.entry_point,
+ param.load);
+
+ if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Ioctl interface for FSL_HV_IOCTL_PARTITION_STOP
+ *
+ * Stop a running partition
+ */
+static long ioctl_stop(struct fsl_hv_ioctl_stop __user *p)
+{
+ struct fsl_hv_ioctl_stop param;
+
+ /* Get the parameters from the user */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_stop)))
+ return -EFAULT;
+
+ param.ret = fh_partition_stop(param.partition);
+
+ if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+/*
+ * Ioctl interface for FSL_HV_IOCTL_MEMCPY
+ *
+ * The FH_MEMCPY hypercall takes an array of address/address/size structures
+ * to represent the data being copied. As a convenience to the user, this
+ * ioctl takes a user-create buffer and a pointer to a guest physically
+ * contiguous buffer in the remote partition, and creates the
+ * address/address/size array for the hypercall.
+ */
+static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
+{
+ struct fsl_hv_ioctl_memcpy param;
+
+ struct page **pages = NULL;
+ void *sg_list_unaligned = NULL;
+ struct fh_sg_list *sg_list = NULL;
+
+ unsigned int num_pages;
+ unsigned long lb_offset; /* Offset within a page of the local buffer */
+
+ unsigned int i;
+ long ret = 0;
+ int num_pinned; /* return value from get_user_pages() */
+ phys_addr_t remote_paddr; /* The next address in the remote buffer */
+ uint32_t count; /* The number of bytes left to copy */
+
+ /* Get the parameters from the user */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_memcpy)))
+ return -EFAULT;
+
+ /*
+ * One partition must be local, the other must be remote. In other
+ * words, if source and target are both -1, or are both not -1, then
+ * return an error.
+ */
+ if ((param.source == -1) == (param.target == -1))
+ return -EINVAL;
+
+ /*
+ * The array of pages returned by get_user_pages() covers only
+ * page-aligned memory. Since the user buffer is probably not
+ * page-aligned, we need to handle the discrepancy.
+ *
+ * We calculate the offset within a page of the S/G list, and make
+ * adjustments accordingly. This will result in a page list that looks
+ * like this:
+ *
+ * ---- <-- first page starts before the buffer
+ * | |
+ * |////|-> ----
+ * |////| | |
+ * ---- | |
+ * | |
+ * ---- | |
+ * |////| | |
+ * |////| | |
+ * |////| | |
+ * ---- | |
+ * | |
+ * ---- | |
+ * |////| | |
+ * |////| | |
+ * |////| | |
+ * ---- | |
+ * | |
+ * ---- | |
+ * |////| | |
+ * |////|-> ----
+ * | | <-- last page ends after the buffer
+ * ----
+ *
+ * The distance between the start of the first page and the start of the
+ * buffer is lb_offset. The hashed (///) areas are the parts of the
+ * page list that contain the actual buffer.
+ *
+ * The advantage of this approach is that the number of pages is
+ * equal to the number of entries in the S/G list that we give to the
+ * hypervisor.
+ */
+ lb_offset = param.local_vaddr & (PAGE_SIZE - 1);
+ num_pages = (param.count + lb_offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ /* Allocate the buffers we need */
+
+ /*
+ * 'pages' is an array of struct page pointers that's initialized by
+ * get_user_pages().
+ */
+ pages = kzalloc(num_pages * sizeof(struct page *), GFP_KERNEL);
+ if (!pages) {
+ pr_debug("fsl-hv: could not allocate page list\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * sg_list is the list of fh_sg_list objects that we pass to the
+ * hypervisor.
+ */
+ sg_list_unaligned = kmalloc(num_pages * sizeof(struct fh_sg_list) +
+ sizeof(struct fh_sg_list) - 1, GFP_KERNEL);
+ if (!sg_list_unaligned) {
+ pr_debug("fsl-hv: could not allocate S/G list\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ sg_list = PTR_ALIGN(sg_list_unaligned, sizeof(struct fh_sg_list));
+
+ /* Get the physical addresses of the source buffer */
+ down_read(¤t->mm->mmap_sem);
+ num_pinned = get_user_pages(current, current->mm,
+ param.local_vaddr - lb_offset, num_pages,
+ (param.source == -1) ? READ : WRITE,
+ 0, pages, NULL);
+ up_read(¤t->mm->mmap_sem);
+
+ if (num_pinned != num_pages) {
+ /* get_user_pages() failed */
+ pr_debug("fsl-hv: could not lock source buffer\n");
+ ret = (num_pinned < 0) ? num_pinned : -EFAULT;
+ goto exit;
+ }
+
+ /*
+ * Build the fh_sg_list[] array. The first page is special
+ * because it's misaligned.
+ */
+ if (param.source == -1) {
+ sg_list[0].source = page_to_phys(pages[0]) + lb_offset;
+ sg_list[0].target = param.remote_paddr;
+ } else {
+ sg_list[0].source = param.remote_paddr;
+ sg_list[0].target = page_to_phys(pages[0]) + lb_offset;
+ }
+ sg_list[0].size = min_t(uint64_t, param.count, PAGE_SIZE - lb_offset);
+
+ remote_paddr = param.remote_paddr + sg_list[0].size;
+ count = param.count - sg_list[0].size;
+
+ for (i = 1; i < num_pages; i++) {
+ if (param.source == -1) {
+ /* local to remote */
+ sg_list[i].source = page_to_phys(pages[i]);
+ sg_list[i].target = remote_paddr;
+ } else {
+ /* remote to local */
+ sg_list[i].source = remote_paddr;
+ sg_list[i].target = page_to_phys(pages[i]);
+ }
+ sg_list[i].size = min_t(uint64_t, count, PAGE_SIZE);
+
+ remote_paddr += sg_list[i].size;
+ count -= sg_list[i].size;
+ }
+
+ param.ret = fh_partition_memcpy(param.source, param.target,
+ virt_to_phys(sg_list), num_pages);
+
+exit:
+ if (pages) {
+ for (i = 0; i < num_pages; i++)
+ if (pages[i])
+ put_page(pages[i]);
+ }
+
+ kfree(sg_list_unaligned);
+ kfree(pages);
+
+ if (!ret)
+ if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
+ return -EFAULT;
+
+ return ret;
+}
+
+/*
+ * Ioctl interface for FSL_HV_IOCTL_DOORBELL
+ *
+ * Ring a doorbell
+ */
+static long ioctl_doorbell(struct fsl_hv_ioctl_doorbell __user *p)
+{
+ struct fsl_hv_ioctl_doorbell param;
+
+ /* Get the parameters from the user. */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_doorbell)))
+ return -EFAULT;
+
+ param.ret = ev_doorbell_send(param.doorbell);
+
+ if (copy_to_user(&p->ret, ¶m.ret, sizeof(__u32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static long ioctl_dtprop(struct fsl_hv_ioctl_prop __user *p, int set)
+{
+ struct fsl_hv_ioctl_prop param;
+ char __user *upath, *upropname;
+ void __user *upropval;
+ char *path = NULL, *propname = NULL;
+ void *propval = NULL;
+ int ret = 0;
+
+ /* Get the parameters from the user. */
+ if (copy_from_user(¶m, p, sizeof(struct fsl_hv_ioctl_prop)))
+ return -EFAULT;
+
+ upath = (char __user *)(uintptr_t)param.path;
+ upropname = (char __user *)(uintptr_t)param.propname;
+ upropval = (void __user *)(uintptr_t)param.propval;
+
+ path = strndup_user(upath, FH_DTPROP_MAX_PATHLEN);
+ if (IS_ERR(path)) {
+ ret = PTR_ERR(path);
+ goto out;
+ }
+
+ propname = strndup_user(upropname, FH_DTPROP_MAX_PATHLEN);
+ if (IS_ERR(propname)) {
+ ret = PTR_ERR(propname);
+ goto out;
+ }
+
+ if (param.proplen > FH_DTPROP_MAX_PROPLEN) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ propval = kmalloc(param.proplen, GFP_KERNEL);
+ if (!propval) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (set) {
+ if (copy_from_user(propval, upropval, param.proplen)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ param.ret = fh_partition_set_dtprop(param.handle,
+ virt_to_phys(path),
+ virt_to_phys(propname),
+ virt_to_phys(propval),
+ param.proplen);
+ } else {
+ param.ret = fh_partition_get_dtprop(param.handle,
+ virt_to_phys(path),
+ virt_to_phys(propname),
+ virt_to_phys(propval),
+ ¶m.proplen);
+
+ if (param.ret == 0) {
+ if (copy_to_user(upropval, propval, param.proplen) ||
+ put_user(param.proplen, &p->proplen)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+ }
+
+ if (put_user(param.ret, &p->ret))
+ ret = -EFAULT;
+
+out:
+ kfree(path);
+ kfree(propval);
+ kfree(propname);
+
+ return ret;
+}
+
+/*
+ * Ioctl main entry point
+ */
+static long fsl_hv_ioctl(struct file *file, unsigned int cmd,
+ unsigned long argaddr)
+{
+ void __user *arg = (void __user *)argaddr;
+ long ret;
+
+ switch (cmd) {
+ case FSL_HV_IOCTL_PARTITION_RESTART:
+ ret = ioctl_restart(arg);
+ break;
+ case FSL_HV_IOCTL_PARTITION_GET_STATUS:
+ ret = ioctl_status(arg);
+ break;
+ case FSL_HV_IOCTL_PARTITION_START:
+ ret = ioctl_start(arg);
+ break;
+ case FSL_HV_IOCTL_PARTITION_STOP:
+ ret = ioctl_stop(arg);
+ break;
+ case FSL_HV_IOCTL_MEMCPY:
+ ret = ioctl_memcpy(arg);
+ break;
+ case FSL_HV_IOCTL_DOORBELL:
+ ret = ioctl_doorbell(arg);
+ break;
+ case FSL_HV_IOCTL_GETPROP:
+ ret = ioctl_dtprop(arg, 0);
+ break;
+ case FSL_HV_IOCTL_SETPROP:
+ ret = ioctl_dtprop(arg, 1);
+ break;
+ default:
+ pr_debug("fsl-hv: bad ioctl dir=%u type=%u cmd=%u size=%u\n",
+ _IOC_DIR(cmd), _IOC_TYPE(cmd), _IOC_NR(cmd),
+ _IOC_SIZE(cmd));
+ return -ENOTTY;
+ }
+
+ return ret;
+}
+
+/* Linked list of processes that have us open */
+static struct list_head db_list;
+
+/* spinlock for db_list */
+static DEFINE_SPINLOCK(db_list_lock);
+
+/* The size of the doorbell event queue. This must be a power of two. */
+#define QSIZE 16
+
+/* Returns the next head/tail pointer, wrapping around the queue if necessary */
+#define nextp(x) (((x) + 1) & (QSIZE - 1))
+
+/* Per-open data structure */
+struct doorbell_queue {
+ struct list_head list;
+ spinlock_t lock;
+ wait_queue_head_t wait;
+ unsigned int head;
+ unsigned int tail;
+ uint32_t q[QSIZE];
+};
+
+/* Linked list of ISRs that we registered */
+struct list_head isr_list;
+
+/* Per-ISR data structure */
+struct doorbell_isr {
+ struct list_head list;
+ unsigned int irq;
+ uint32_t doorbell; /* The doorbell handle */
+ uint32_t partition; /* The partition handle, if used */
+};
+
+/*
+ * Add a doorbell to all of the doorbell queues
+ */
+static void fsl_hv_queue_doorbell(uint32_t doorbell)
+{
+ struct doorbell_queue *dbq;
+ unsigned long flags;
+
+ /* Prevent another core from modifying db_list */
+ spin_lock_irqsave(&db_list_lock, flags);
+
+ list_for_each_entry(dbq, &db_list, list) {
+ if (dbq->head != nextp(dbq->tail)) {
+ dbq->q[dbq->tail] = doorbell;
+ /*
+ * This memory barrier eliminates the need to grab
+ * the spinlock for dbq.
+ */
+ smp_wmb();
+ dbq->tail = nextp(dbq->tail);
+ wake_up_interruptible(&dbq->wait);
+ }
+ }
+
+ spin_unlock_irqrestore(&db_list_lock, flags);
+}
+
+/*
+ * Interrupt handler for all doorbells
+ *
+ * We use the same interrupt handler for all doorbells. Whenever a doorbell
+ * is rung, and we receive an interrupt, we just put the handle for that
+ * doorbell (passed to us as *data) into all of the queues.
+ */
+static irqreturn_t fsl_hv_isr(int irq, void *data)
+{
+ fsl_hv_queue_doorbell((uintptr_t) data);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * State change thread function
+ *
+ * The state change notification arrives in an interrupt, but we can't call
+ * blocking_notifier_call_chain() in an interrupt handler. We could call
+ * atomic_notifier_call_chain(), but that would require the clients' call-back
+ * function to run in interrupt context. Since we don't want to impose that
+ * restriction on the clients, we use a threaded IRQ to process the
+ * notification in kernel context.
+ */
+static irqreturn_t fsl_hv_state_change_thread(int irq, void *data)
+{
+ struct doorbell_isr *dbisr = data;
+
+ blocking_notifier_call_chain(&failover_subscribers, dbisr->partition,
+ NULL);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Interrupt handler for state-change doorbells
+ */
+static irqreturn_t fsl_hv_state_change_isr(int irq, void *data)
+{
+ unsigned int status;
+ struct doorbell_isr *dbisr = data;
+ int ret;
+
+ /* It's still a doorbell, so add it to all the queues. */
+ fsl_hv_queue_doorbell(dbisr->doorbell);
+
+ /* Determine the new state, and if it's stopped, notify the clients. */
+ ret = fh_partition_get_status(dbisr->partition, &status);
+ if (!ret && (status == FH_PARTITION_STOPPED))
+ return IRQ_WAKE_THREAD;
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Returns a bitmask indicating whether a read will block
+ */
+static unsigned int fsl_hv_poll(struct file *filp, struct poll_table_struct *p)
+{
+ struct doorbell_queue *dbq = filp->private_data;
+ unsigned long flags;
+ unsigned int mask;
+
+ spin_lock_irqsave(&dbq->lock, flags);
+
+ poll_wait(filp, &dbq->wait, p);
+ mask = (dbq->head == dbq->tail) ? 0 : (POLLIN | POLLRDNORM);
+
+ spin_unlock_irqrestore(&dbq->lock, flags);
+
+ return mask;
+}
+
+/*
+ * Return the handles for any incoming doorbells
+ *
+ * If there are doorbell handles in the queue for this open instance, then
+ * return them to the caller as an array of 32-bit integers. Otherwise,
+ * block until there is at least one handle to return.
+ */
+static ssize_t fsl_hv_read(struct file *filp, char __user *buf, size_t len,
+ loff_t *off)
+{
+ struct doorbell_queue *dbq = filp->private_data;
+ uint32_t __user *p = (uint32_t __user *) buf; /* for put_user() */
+ unsigned long flags;
+ ssize_t count = 0;
+
+ /* Make sure we stop when the user buffer is full. */
+ while (len >= sizeof(uint32_t)) {
+ uint32_t dbell; /* Local copy of doorbell queue data */
+
+ spin_lock_irqsave(&dbq->lock, flags);
+
+ /*
+ * If the queue is empty, then either we're done or we need
+ * to block. If the application specified O_NONBLOCK, then
+ * we return the appropriate error code.
+ */
+ if (dbq->head == dbq->tail) {
+ spin_unlock_irqrestore(&dbq->lock, flags);
+ if (count)
+ break;
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ if (wait_event_interruptible(dbq->wait,
+ dbq->head != dbq->tail))
+ return -ERESTARTSYS;
+ continue;
+ }
+
+ /*
+ * Even though we have an smp_wmb() in the ISR, the core
+ * might speculatively execute the "dbell = ..." below while
+ * it's evaluating the if-statement above. In that case, the
+ * value put into dbell could be stale if the core accepts the
+ * speculation. To prevent that, we need a read memory barrier
+ * here as well.
+ */
+ smp_rmb();
+
+ /* Copy the data to a temporary local buffer, because
+ * we can't call copy_to_user() from inside a spinlock
+ */
+ dbell = dbq->q[dbq->head];
+ dbq->head = nextp(dbq->head);
+
+ spin_unlock_irqrestore(&dbq->lock, flags);
+
+ if (put_user(dbell, p))
+ return -EFAULT;
+ p++;
+ count += sizeof(uint32_t);
+ len -= sizeof(uint32_t);
+ }
+
+ return count;
+}
+
+/*
+ * Open the driver and prepare for reading doorbells.
+ *
+ * Every time an application opens the driver, we create a doorbell queue
+ * for that file handle. This queue is used for any incoming doorbells.
+ */
+static int fsl_hv_open(struct inode *inode, struct file *filp)
+{
+ struct doorbell_queue *dbq;
+ unsigned long flags;
+ int ret = 0;
+
+ dbq = kzalloc(sizeof(struct doorbell_queue), GFP_KERNEL);
+ if (!dbq) {
+ pr_err("fsl-hv: out of memory\n");
+ return -ENOMEM;
+ }
+
+ spin_lock_init(&dbq->lock);
+ init_waitqueue_head(&dbq->wait);
+
+ spin_lock_irqsave(&db_list_lock, flags);
+ list_add(&dbq->list, &db_list);
+ spin_unlock_irqrestore(&db_list_lock, flags);
+
+ filp->private_data = dbq;
+
+ return ret;
+}
+
+/*
+ * Close the driver
+ */
+static int fsl_hv_close(struct inode *inode, struct file *filp)
+{
+ struct doorbell_queue *dbq = filp->private_data;
+ unsigned long flags;
+
+ int ret = 0;
+
+ spin_lock_irqsave(&db_list_lock, flags);
+ list_del(&dbq->list);
+ spin_unlock_irqrestore(&db_list_lock, flags);
+
+ kfree(dbq);
+
+ return ret;
+}
+
+static const struct file_operations fsl_hv_fops = {
+ .owner = THIS_MODULE,
+ .open = fsl_hv_open,
+ .release = fsl_hv_close,
+ .poll = fsl_hv_poll,
+ .read = fsl_hv_read,
+ .unlocked_ioctl = fsl_hv_ioctl,
+};
+
+static struct miscdevice fsl_hv_misc_dev = {
+ MISC_DYNAMIC_MINOR,
+ "fsl-hv",
+ &fsl_hv_fops
+};
+
+static irqreturn_t fsl_hv_shutdown_isr(int irq, void *data)
+{
+ orderly_poweroff(false);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Returns the handle of the parent of the given node
+ *
+ * The handle is the value of the 'hv-handle' property
+ */
+static int get_parent_handle(struct device_node *np)
+{
+ struct device_node *parent;
+ const uint32_t *prop;
+ uint32_t handle;
+ int len;
+
+ parent = of_get_parent(np);
+ if (!parent)
+ /* It's not really possible for this to fail */
+ return -ENODEV;
+
+ /*
+ * The proper name for the handle property is "hv-handle", but some
+ * older versions of the hypervisor used "reg".
+ */
+ prop = of_get_property(parent, "hv-handle", &len);
+ if (!prop)
+ prop = of_get_property(parent, "reg", &len);
+
+ if (!prop || (len != sizeof(uint32_t))) {
+ /* This can happen only if the node is malformed */
+ of_node_put(parent);
+ return -ENODEV;
+ }
+
+ handle = be32_to_cpup(prop);
+ of_node_put(parent);
+
+ return handle;
+}
+
+/*
+ * Register a callback for failover events
+ *
+ * This function is called by device drivers to register their callback
+ * functions for fail-over events.
+ */
+int fsl_hv_failover_register(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&failover_subscribers, nb);
+}
+EXPORT_SYMBOL(fsl_hv_failover_register);
+
+/*
+ * Unregister a callback for failover events
+ */
+int fsl_hv_failover_unregister(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&failover_subscribers, nb);
+}
+EXPORT_SYMBOL(fsl_hv_failover_unregister);
+
+/*
+ * Return TRUE if we're running under FSL hypervisor
+ *
+ * This function checks to see if we're running under the Freescale
+ * hypervisor, and returns zero if we're not, or non-zero if we are.
+ *
+ * First, it checks if MSR[GS]==1, which means we're running under some
+ * hypervisor. Then it checks if there is a hypervisor node in the device
+ * tree. Currently, that means there needs to be a node in the root called
+ * "hypervisor" and which has a property named "fsl,hv-version".
+ */
+static int has_fsl_hypervisor(void)
+{
+ struct device_node *node;
+ int ret;
+
+ if (!(mfmsr() & MSR_GS))
+ return 0;
+
+ node = of_find_node_by_path("/hypervisor");
+ if (!node)
+ return 0;
+
+ ret = of_find_property(node, "fsl,hv-version", NULL) != NULL;
+
+ of_node_put(node);
+
+ return ret;
+}
+
+/*
+ * Freescale hypervisor management driver init
+ *
+ * This function is called when this module is loaded.
+ *
+ * Register ourselves as a miscellaneous driver. This will register the
+ * fops structure and create the right sysfs entries for udev.
+ */
+static int __init fsl_hypervisor_init(void)
+{
+ struct device_node *np;
+ struct doorbell_isr *dbisr, *n;
+ int ret;
+
+ pr_info("Freescale hypervisor management driver\n");
+
+ if (!has_fsl_hypervisor()) {
+ pr_info("fsl-hv: no hypervisor found\n");
+ return -ENODEV;
+ }
+
+ ret = misc_register(&fsl_hv_misc_dev);
+ if (ret) {
+ pr_err("fsl-hv: cannot register device\n");
+ return ret;
+ }
+
+ INIT_LIST_HEAD(&db_list);
+ INIT_LIST_HEAD(&isr_list);
+
+ for_each_compatible_node(np, NULL, "epapr,hv-receive-doorbell") {
+ unsigned int irq;
+ const uint32_t *handle;
+
+ handle = of_get_property(np, "interrupts", NULL);
+ irq = irq_of_parse_and_map(np, 0);
+ if (!handle || (irq == NO_IRQ)) {
+ pr_err("fsl-hv: no 'interrupts' property in %s node\n",
+ np->full_name);
+ continue;
+ }
+
+ dbisr = kzalloc(sizeof(*dbisr), GFP_KERNEL);
+ if (!dbisr)
+ goto out_of_memory;
+
+ dbisr->irq = irq;
+ dbisr->doorbell = be32_to_cpup(handle);
+
+ if (of_device_is_compatible(np, "fsl,hv-shutdown-doorbell")) {
+ /* The shutdown doorbell gets its own ISR */
+ ret = request_irq(irq, fsl_hv_shutdown_isr, 0,
+ np->name, NULL);
+ } else if (of_device_is_compatible(np,
+ "fsl,hv-state-change-doorbell")) {
+ /*
+ * The state change doorbell triggers a notification if
+ * the state of the managed partition changes to
+ * "stopped". We need a separate interrupt handler for
+ * that, and we also need to know the handle of the
+ * target partition, not just the handle of the
+ * doorbell.
+ */
+ dbisr->partition = ret = get_parent_handle(np);
+ if (ret < 0) {
+ pr_err("fsl-hv: node %s has missing or "
+ "malformed parent\n", np->full_name);
+ kfree(dbisr);
+ continue;
+ }
+ ret = request_threaded_irq(irq, fsl_hv_state_change_isr,
+ fsl_hv_state_change_thread,
+ 0, np->name, dbisr);
+ } else
+ ret = request_irq(irq, fsl_hv_isr, 0, np->name, dbisr);
+
+ if (ret < 0) {
+ pr_err("fsl-hv: could not request irq %u for node %s\n",
+ irq, np->full_name);
+ kfree(dbisr);
+ continue;
+ }
+
+ list_add(&dbisr->list, &isr_list);
+
+ pr_info("fsl-hv: registered handler for doorbell %u\n",
+ dbisr->doorbell);
+ }
+
+ return 0;
+
+out_of_memory:
+ list_for_each_entry_safe(dbisr, n, &isr_list, list) {
+ free_irq(dbisr->irq, dbisr);
+ list_del(&dbisr->list);
+ kfree(dbisr);
+ }
+
+ misc_deregister(&fsl_hv_misc_dev);
+
+ return -ENOMEM;
+}
+
+/*
+ * Freescale hypervisor management driver termination
+ *
+ * This function is called when this driver is unloaded.
+ */
+static void __exit fsl_hypervisor_exit(void)
+{
+ struct doorbell_isr *dbisr, *n;
+
+ list_for_each_entry_safe(dbisr, n, &isr_list, list) {
+ free_irq(dbisr->irq, dbisr);
+ list_del(&dbisr->list);
+ kfree(dbisr);
+ }
+
+ misc_deregister(&fsl_hv_misc_dev);
+}
+
+module_init(fsl_hypervisor_init);
+module_exit(fsl_hypervisor_exit);
+
+MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
+MODULE_DESCRIPTION("Freescale hypervisor management driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 75cf611..68c341a 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -134,6 +134,7 @@ header-y += firewire-cdev.h
header-y += firewire-constants.h
header-y += flat.h
header-y += fs.h
+header-y += fsl_hypervisor.h
header-y += fuse.h
header-y += futex.h
header-y += gameport.h
diff --git a/include/linux/fsl_hypervisor.h b/include/linux/fsl_hypervisor.h
new file mode 100644
index 0000000..1cebaee
--- /dev/null
+++ b/include/linux/fsl_hypervisor.h
@@ -0,0 +1,241 @@
+/*
+ * Freescale hypervisor ioctl and kernel interface
+ *
+ * Copyright (C) 2008-2011 Freescale Semiconductor, Inc.
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Freescale Semiconductor nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * This software is provided by Freescale Semiconductor "as is" and any
+ * express or implied warranties, including, but not limited to, the implied
+ * warranties of merchantability and fitness for a particular purpose are
+ * disclaimed. In no event shall Freescale Semiconductor be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential damages
+ * (including, but not limited to, procurement of substitute goods or services;
+ * loss of use, data, or profits; or business interruption) however caused and
+ * on any theory of liability, whether in contract, strict liability, or tort
+ * (including negligence or otherwise) arising in any way out of the use of this
+ * software, even if advised of the possibility of such damage.
+ *
+ * This file is used by the Freescale hypervisor management driver. It can
+ * also be included by applications that need to communicate with the driver
+ * via the ioctl interface.
+ */
+
+#ifndef FSL_HYPERVISOR_H
+#define FSL_HYPERVISOR_H
+
+#include <linux/types.h>
+
+/**
+ * struct fsl_hv_ioctl_restart - restart a partition
+ * @ret: return error code from the hypervisor
+ * @partition: the ID of the partition to restart, or -1 for the
+ * calling partition
+ *
+ * Used by FSL_HV_IOCTL_PARTITION_RESTART
+ */
+struct fsl_hv_ioctl_restart {
+ __u32 ret;
+ __u32 partition;
+};
+
+/**
+ * struct fsl_hv_ioctl_status - get a partition's status
+ * @ret: return error code from the hypervisor
+ * @partition: the ID of the partition to query, or -1 for the
+ * calling partition
+ * @status: The returned status of the partition
+ *
+ * Used by FSL_HV_IOCTL_PARTITION_GET_STATUS
+ *
+ * Values of 'status':
+ * 0 = Stopped
+ * 1 = Running
+ * 2 = Starting
+ * 3 = Stopping
+ */
+struct fsl_hv_ioctl_status {
+ __u32 ret;
+ __u32 partition;
+ __u32 status;
+};
+
+/**
+ * struct fsl_hv_ioctl_start - start a partition
+ * @ret: return error code from the hypervisor
+ * @partition: the ID of the partition to control
+ * @entry_point: The offset within the guest IMA to start execution
+ * @load: If non-zero, reload the partition's images before starting
+ *
+ * Used by FSL_HV_IOCTL_PARTITION_START
+ */
+struct fsl_hv_ioctl_start {
+ __u32 ret;
+ __u32 partition;
+ __u32 entry_point;
+ __u32 load;
+};
+
+/**
+ * struct fsl_hv_ioctl_stop - stop a partition
+ * @ret: return error code from the hypervisor
+ * @partition: the ID of the partition to stop, or -1 for the calling
+ * partition
+ *
+ * Used by FSL_HV_IOCTL_PARTITION_STOP
+ */
+struct fsl_hv_ioctl_stop {
+ __u32 ret;
+ __u32 partition;
+};
+
+/**
+ * struct fsl_hv_ioctl_memcpy - copy memory between partitions
+ * @ret: return error code from the hypervisor
+ * @source: the partition ID of the source partition, or -1 for this
+ * partition
+ * @target: the partition ID of the target partition, or -1 for this
+ * partition
+ * @reserved: reserved, must be set to 0
+ * @local_addr: user-space virtual address of a buffer in the local
+ * partition
+ * @remote_addr: guest physical address of a buffer in the
+ * remote partition
+ * @count: the number of bytes to copy. Both the local and remote
+ * buffers must be at least 'count' bytes long
+ *
+ * Used by FSL_HV_IOCTL_MEMCPY
+ *
+ * The 'local' partition is the partition that calls this ioctl. The
+ * 'remote' partition is a different partition. The data is copied from
+ * the 'source' paritition' to the 'target' partition.
+ *
+ * The buffer in the remote partition must be guest physically
+ * contiguous.
+ *
+ * This ioctl does not support copying memory between two remote
+ * partitions or within the same partition, so either 'source' or
+ * 'target' (but not both) must be -1. In other words, either
+ *
+ * source == local and target == remote
+ * or
+ * source == remote and target == local
+ */
+struct fsl_hv_ioctl_memcpy {
+ __u32 ret;
+ __u32 source;
+ __u32 target;
+ __u32 reserved; /* padding to ensure local_vaddr is aligned */
+ __u64 local_vaddr;
+ __u64 remote_paddr;
+ __u64 count;
+};
+
+/**
+ * struct fsl_hv_ioctl_doorbell - ring a doorbell
+ * @ret: return error code from the hypervisor
+ * @doorbell: the handle of the doorbell to ring doorbell
+ *
+ * Used by FSL_HV_IOCTL_DOORBELL
+ */
+struct fsl_hv_ioctl_doorbell {
+ __u32 ret;
+ __u32 doorbell;
+};
+
+/**
+ * struct fsl_hv_ioctl_prop - get/set a device tree property
+ * @ret: return error code from the hypervisor
+ * @handle: handle of partition whose tree to access
+ * @path: virtual address of path name of node to access
+ * @propname: virtual address of name of property to access
+ * @propval: virtual address of property data buffer
+ * @proplen: Size of property data buffer
+ * @reserved: reserved, must be set to 0
+ *
+ * Used by FSL_HV_IOCTL_DOORBELL
+ */
+struct fsl_hv_ioctl_prop {
+ __u32 ret;
+ __u32 handle;
+ __u64 path;
+ __u64 propname;
+ __u64 propval;
+ __u32 proplen;
+ __u32 reserved; /* padding to ensure structure is aligned */
+};
+
+/* The ioctl type, documented in ioctl-number.txt */
+#define FSL_HV_IOCTL_TYPE 0xAF
+
+/* Restart another partition */
+#define FSL_HV_IOCTL_PARTITION_RESTART \
+ _IOWR(FSL_HV_IOCTL_TYPE, 1, struct fsl_hv_ioctl_restart)
+
+/* Get a partition's status */
+#define FSL_HV_IOCTL_PARTITION_GET_STATUS \
+ _IOWR(FSL_HV_IOCTL_TYPE, 2, struct fsl_hv_ioctl_status)
+
+/* Boot another partition */
+#define FSL_HV_IOCTL_PARTITION_START \
+ _IOWR(FSL_HV_IOCTL_TYPE, 3, struct fsl_hv_ioctl_start)
+
+/* Stop this or another partition */
+#define FSL_HV_IOCTL_PARTITION_STOP \
+ _IOWR(FSL_HV_IOCTL_TYPE, 4, struct fsl_hv_ioctl_stop)
+
+/* Copy data from one partition to another */
+#define FSL_HV_IOCTL_MEMCPY \
+ _IOWR(FSL_HV_IOCTL_TYPE, 5, struct fsl_hv_ioctl_memcpy)
+
+/* Ring a doorbell */
+#define FSL_HV_IOCTL_DOORBELL \
+ _IOWR(FSL_HV_IOCTL_TYPE, 6, struct fsl_hv_ioctl_doorbell)
+
+/* Get a property from another guest's device tree */
+#define FSL_HV_IOCTL_GETPROP \
+ _IOWR(FSL_HV_IOCTL_TYPE, 7, struct fsl_hv_ioctl_prop)
+
+/* Set a property in another guest's device tree */
+#define FSL_HV_IOCTL_SETPROP \
+ _IOWR(FSL_HV_IOCTL_TYPE, 8, struct fsl_hv_ioctl_prop)
+
+#ifdef __KERNEL__
+
+/**
+ * fsl_hv_event_register() - register a callback for failover events
+ * @nb: pointer to caller-supplied notifier_block structure
+ *
+ * This function is called by device drivers to register their callback
+ * functions for fail-over events.
+ *
+ * The caller should allocate a notifier_block object and initialize the
+ * 'priority' and 'notifier_call' fields.
+ */
+int fsl_hv_failover_register(struct notifier_block *nb);
+
+/**
+ * fsl_hv_event_unregister() - unregister a callback for failover events
+ * @nb: the same 'nb' used in previous fsl_hv_failover_register call
+ */
+int fsl_hv_failover_unregister(struct notifier_block *nb);
+
+#endif
+
+#endif
--
1.7.3.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox