From: "Rafał Bilski" <rafalbilski@interia.pl>
To: linux-kernel@vger.kernel.org
Subject: Longhaul - infrastructure(?) proposal
Date: Thu, 29 Jun 2006 22:26:17 +0200 [thread overview]
Message-ID: <44A43769.5040601@interia.pl> (raw)
In case that flushing and disabling caches will not work.
(but it is possible that I do above in wrong way).
Would this code below be acceptable as infrastructure?
Is this infrastructure or maybe hack? Are there any HOWTO
write correct infrastructure?
This is draft/proposal.
Can I continue in this way or I shouldn't?
This code (more correct version) will be included in
longhaul.c. There should be include file "cpufreq_longhaul.h"
for drivers knowing about "longhaul problem".
Driver would have all code for longhaul in
"#ifdef CONFIG_X86_LONGHAUL / #else / #endif".
Basic support for longhaul in driver:
1. driver calls longhaul_bmdma_register("driver_name_wq")
at init,
2. driver calls longhaul_bmdma_begin before starting BMDMA
with function that is starting DMA for this driver
(or in case of via-rhine driver with function which queues
packet in hardware queue). You can do it multiple times
before calling longhaul_bmdma_end for the first time,
3. driver calls longhaul_bmdma_end after BMDMA transfer is
completed (via-rhine - after packet was send).
Longhaul would simply lock write longhaul_sem before
CPU frequency change.
Sorry to bother You all again.
Rafał
---
/*
* Longhaul "infrastructure" for bus master DMA
*/
struct longhaul_work {
struct list_head entry;
struct work_struct work;
struct longhaul_data *data;
void (*device_func) (void *data);
void *device_data;
};
struct longhaul_data {
struct workqueue_struct *wq;
spinlock_t lock;
struct list_head work_unused;
struct list_head work_inuse;
struct list_head work_used;
};
/* Access control for PCI bus */
static struct rw_semaphore longhaul_sem;
struct longhaul_data *longhaul_bmdma_register(char *name)
{
struct longhaul_data *longdata;
struct longhaul_work *longwork;
struct workqueue_struct *workqueue;
longdata = kmalloc(sizeof(struct longhaul_data), GFP_KERNEL);
if (longdata == NULL)
return NULL;
spin_lock_init(&longdata->lock);
INIT_LIST_HEAD(&longdata->work_unused);
INIT_LIST_HEAD(&longdata->work_inuse);
INIT_LIST_HEAD(&longdata->work_used);
longwork = kmalloc(sizeof(struct longhaul_work), GFP_KERNEL);
if (longwork == NULL) {
goto free_longdata;
}
INIT_WORK(&longwork->work, &longhaul_bmdma_work, NULL);
list_add(longwork, &longdata->work_unused);
longwork->data = longdata;
workqueue = create_singlethread_workqueue(name);
if (workqueue == NULL) {
printk(KERN_ERR PFX "Can't create workqueue \"%s\".\n", name);
goto free_longwork;
}
longdata->wq = workqueue;
return longdata;
free_longwork:
kfree(longwork);
free_longdata:
kfree(longdata);
return NULL;
}
EXPORT_SYMBOL(longhaul_bmdma_register);
void longhaul_bmdma_unregister(struct longhaul_data *longdata)
{
}
EXPORT_SYMBOL(longhaul_bmdma_unregister);
static void longhaul_bmdma_work(void *data)
{
struct longhaul_work *longwork = data;
struct longhaul_data *longdata = longwork->data;
unsigned long flags;
down_read(&longhaul_sem);
longdata->device_func(longdata->device_data);
spin_lock_irqsave(&longdata->lock, flags);
list_move(longwork, &longdata->work_used);
spin_unlock_irqrestore(&longdata->lock, flags);
}
int longhaul_bmdma_begin(struct longhaul_data *longdata,
void (*device_func) (void *data),
void *device_data);
{
struct longhaul_work *longwork;
unsigned long flags;
spin_lock_irqsave(&longdata->lock, flags);
if ( list_empty(&longdata->work_unused) ) {
longwork = kmalloc(sizeof(struct longhaul_work), GFP_ATOMIC);
if (longwork == NULL) {
spin_unlock_irqrestore(&longdata->lock, flags);
return -ENOMEM;
}
INIT_WORK(&longwork->work, &longhaul_bmdma_work, NULL);
longwork->data = longdata;
list_add(longwork, &longdata->work_inuse);
} else {
longwork = longdata->work_unused->next;
list_move(longwork, &longdata->work_inuse);
}
spin_unlock_irqrestore(&longdata->lock, flags);
longwork->device_func = device_func;
longwork->device_data = device_data;
PREPARE_WORK(longwork, &longhaul_bmdma_work, (void*)longwork);
queue_work(longdata->wq, longwork);
return 0;
}
EXPORT_SYMBOL(longhaul_bmdma_begin);
void longhaul_bmdma_end(struct longhaul_data *longdata)
{
struct list_head pos;
unsigned long flags;
spin_lock_irqsave(&longdata->lock, flags);
if ( !list_empty(&longdata->work_used) ) {
list_for_each(pos, &longdata->work_used) {
list_move(longwork, &longdata->work_unused);
}
}
spin_unlock_irqrestore(&longdata->lock, flags);
up_read(&longhaul_sem);
}
EXPORT_SYMBOL(longhaul_bmdma_end);
----------------------------------------------------------------------
PS. Fajny portal... >>> http://link.interia.pl/f196a
next reply other threads:[~2006-06-29 20:27 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-06-29 20:26 Rafał Bilski [this message]
-- strict thread matches above, loose matches on Subject: below --
2006-06-29 15:05 Longhaul - infrastructure(?) proposal Rafał Bilski
2006-06-29 19:28 ` Dave Jones
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44A43769.5040601@interia.pl \
--to=rafalbilski@interia.pl \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.