mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
[SCSI] Merge branch 'linus'
Conflicts: drivers/message/fusion/mptsas.c fixed up conflict between req->data_len accessors and mptsas driver updates. Signed-off-by: James Bottomley <[email protected]>
This commit is contained in:
commit
82681a318f
1794 changed files with 103107 additions and 34819 deletions
|
|
@ -116,9 +116,6 @@ int acpi_pci_bind(struct acpi_device *device)
|
|||
struct acpi_pci_data *pdata;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_handle handle;
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus;
|
||||
|
||||
|
||||
if (!device || !device->parent)
|
||||
return -EINVAL;
|
||||
|
|
@ -176,20 +173,9 @@ int acpi_pci_bind(struct acpi_device *device)
|
|||
* Locate matching device in PCI namespace. If it doesn't exist
|
||||
* this typically means that the device isn't currently inserted
|
||||
* (e.g. docking station, port replicator, etc.).
|
||||
* We cannot simply search the global pci device list, since
|
||||
* PCI devices are added to the global pci list when the root
|
||||
* bridge start ops are run, which may not have happened yet.
|
||||
*/
|
||||
bus = pci_find_bus(data->id.segment, data->id.bus);
|
||||
if (bus) {
|
||||
list_for_each_entry(dev, &bus->devices, bus_list) {
|
||||
if (dev->devfn == PCI_DEVFN(data->id.device,
|
||||
data->id.function)) {
|
||||
data->dev = dev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
data->dev = pci_get_slot(pdata->bus,
|
||||
PCI_DEVFN(data->id.device, data->id.function));
|
||||
if (!data->dev) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Device %04x:%02x:%02x.%d not present in PCI namespace\n",
|
||||
|
|
@ -259,9 +245,10 @@ int acpi_pci_bind(struct acpi_device *device)
|
|||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
if (result)
|
||||
if (result) {
|
||||
pci_dev_put(data->dev);
|
||||
kfree(data);
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -303,6 +290,7 @@ static int acpi_pci_unbind(struct acpi_device *device)
|
|||
if (data->dev->subordinate) {
|
||||
acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
|
||||
}
|
||||
pci_dev_put(data->dev);
|
||||
kfree(data);
|
||||
|
||||
end:
|
||||
|
|
|
|||
|
|
@ -401,7 +401,8 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|||
/* Interrupt Line values above 0xF are forbidden */
|
||||
if (dev->irq > 0 && (dev->irq <= 0xF)) {
|
||||
printk(" - using IRQ %d\n", dev->irq);
|
||||
acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE,
|
||||
acpi_register_gsi(&dev->dev, dev->irq,
|
||||
ACPI_LEVEL_SENSITIVE,
|
||||
ACPI_ACTIVE_LOW);
|
||||
return 0;
|
||||
} else {
|
||||
|
|
@ -410,7 +411,7 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|||
}
|
||||
}
|
||||
|
||||
rc = acpi_register_gsi(gsi, triggering, polarity);
|
||||
rc = acpi_register_gsi(&dev->dev, gsi, triggering, polarity);
|
||||
if (rc < 0) {
|
||||
dev_warn(&dev->dev, "PCI INT %c: failed to register GSI\n",
|
||||
pin_name(pin));
|
||||
|
|
|
|||
|
|
@ -844,7 +844,7 @@ static int acpi_processor_add(struct acpi_device *device)
|
|||
if (!pr)
|
||||
return -ENOMEM;
|
||||
|
||||
if (!alloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
|
||||
if (!zalloc_cpumask_var(&pr->throttling.shared_cpu_map, GFP_KERNEL)) {
|
||||
kfree(pr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -148,6 +148,9 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
|
|||
if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))
|
||||
return;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_AMDC1E))
|
||||
type = ACPI_STATE_C1;
|
||||
|
||||
/*
|
||||
* Check, if one of the previous states already marked the lapic
|
||||
* unstable
|
||||
|
|
@ -611,6 +614,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
|
|||
switch (cx->type) {
|
||||
case ACPI_STATE_C1:
|
||||
cx->valid = 1;
|
||||
acpi_timer_check_state(i, pr, cx);
|
||||
break;
|
||||
|
||||
case ACPI_STATE_C2:
|
||||
|
|
@ -830,11 +834,12 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
|
|||
|
||||
/* Do not access any ACPI IO ports in suspend path */
|
||||
if (acpi_idle_suspend) {
|
||||
acpi_safe_halt();
|
||||
local_irq_enable();
|
||||
cpu_relax();
|
||||
return 0;
|
||||
}
|
||||
|
||||
acpi_state_timer_broadcast(pr, cx, 1);
|
||||
kt1 = ktime_get_real();
|
||||
acpi_idle_do_entry(cx);
|
||||
kt2 = ktime_get_real();
|
||||
|
|
@ -842,6 +847,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
|
|||
|
||||
local_irq_enable();
|
||||
cx->usage++;
|
||||
acpi_state_timer_broadcast(pr, cx, 0);
|
||||
|
||||
return idle_time;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -309,9 +309,15 @@ static int acpi_processor_get_performance_states(struct acpi_processor *pr)
|
|||
(u32) px->bus_master_latency,
|
||||
(u32) px->control, (u32) px->status));
|
||||
|
||||
if (!px->core_frequency) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Invalid _PSS data: freq is zero\n");
|
||||
/*
|
||||
* Check that ACPI's u64 MHz will be valid as u32 KHz in cpufreq
|
||||
*/
|
||||
if (!px->core_frequency ||
|
||||
((u32)(px->core_frequency * 1000) !=
|
||||
(px->core_frequency * 1000))) {
|
||||
printk(KERN_ERR FW_BUG PREFIX
|
||||
"Invalid BIOS _PSS frequency: 0x%llx MHz\n",
|
||||
px->core_frequency);
|
||||
result = -EFAULT;
|
||||
kfree(pr->performance->states);
|
||||
goto end;
|
||||
|
|
|
|||
|
|
@ -840,7 +840,7 @@ static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
|
|||
state = acpi_get_throttling_state(pr, value);
|
||||
if (state == -1) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"Invalid throttling state, reset\n"));
|
||||
"Invalid throttling state, reset"));
|
||||
state = 0;
|
||||
ret = acpi_processor_set_throttling(pr, state);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -570,6 +570,22 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_set_bqc_offset,
|
||||
.ident = "eMachines E510",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = video_set_bqc_offset,
|
||||
.ident = "Acer Aspire 5315",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
|
||||
},
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -2334,7 +2350,7 @@ static int __init acpi_video_init(void)
|
|||
return acpi_video_register();
|
||||
}
|
||||
|
||||
void __exit acpi_video_exit(void)
|
||||
void acpi_video_exit(void)
|
||||
{
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_video_bus);
|
||||
|
|
|
|||
|
|
@ -77,8 +77,6 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
|
|||
size_t size);
|
||||
static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
|
||||
ssize_t size);
|
||||
#define MAX_SLOTS 8
|
||||
#define MAX_RETRY 15
|
||||
|
||||
enum {
|
||||
AHCI_PCI_BAR = 5,
|
||||
|
|
@ -220,6 +218,7 @@ enum {
|
|||
AHCI_HFLAG_NO_HOTPLUG = (1 << 7), /* ignore PxSERR.DIAG.N */
|
||||
AHCI_HFLAG_SECT255 = (1 << 8), /* max 255 sectors */
|
||||
AHCI_HFLAG_YES_NCQ = (1 << 9), /* force NCQ cap on */
|
||||
AHCI_HFLAG_NO_SUSPEND = (1 << 10), /* don't suspend */
|
||||
|
||||
/* ap->flags bits */
|
||||
|
||||
|
|
@ -230,6 +229,10 @@ enum {
|
|||
|
||||
ICH_MAP = 0x90, /* ICH MAP register */
|
||||
|
||||
/* em constants */
|
||||
EM_MAX_SLOTS = 8,
|
||||
EM_MAX_RETRY = 5,
|
||||
|
||||
/* em_ctl bits */
|
||||
EM_CTL_RST = (1 << 9), /* Reset */
|
||||
EM_CTL_TM = (1 << 8), /* Transmit Message */
|
||||
|
|
@ -281,8 +284,8 @@ struct ahci_port_priv {
|
|||
unsigned int ncq_saw_dmas:1;
|
||||
unsigned int ncq_saw_sdb:1;
|
||||
u32 intr_mask; /* interrupts to enable */
|
||||
struct ahci_em_priv em_priv[MAX_SLOTS];/* enclosure management info
|
||||
* per PM slot */
|
||||
/* enclosure management info per PM slot */
|
||||
struct ahci_em_priv em_priv[EM_MAX_SLOTS];
|
||||
};
|
||||
|
||||
static int ahci_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
||||
|
|
@ -312,7 +315,6 @@ static void ahci_error_handler(struct ata_port *ap);
|
|||
static void ahci_post_internal_cmd(struct ata_queued_cmd *qc);
|
||||
static int ahci_port_resume(struct ata_port *ap);
|
||||
static void ahci_dev_config(struct ata_device *dev);
|
||||
static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc, void *cmd_tbl);
|
||||
static void ahci_fill_cmd_slot(struct ahci_port_priv *pp, unsigned int tag,
|
||||
u32 opts);
|
||||
#ifdef CONFIG_PM
|
||||
|
|
@ -403,14 +405,14 @@ static struct ata_port_operations ahci_sb600_ops = {
|
|||
#define AHCI_HFLAGS(flags) .private_data = (void *)(flags)
|
||||
|
||||
static const struct ata_port_info ahci_port_info[] = {
|
||||
/* board_ahci */
|
||||
[board_ahci] =
|
||||
{
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_ops,
|
||||
},
|
||||
/* board_ahci_vt8251 */
|
||||
[board_ahci_vt8251] =
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_PMP),
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
|
|
@ -418,7 +420,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
|||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_vt8251_ops,
|
||||
},
|
||||
/* board_ahci_ign_iferr */
|
||||
[board_ahci_ign_iferr] =
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_IGN_IRQ_IF_ERR),
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
|
|
@ -426,17 +428,16 @@ static const struct ata_port_info ahci_port_info[] = {
|
|||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_ops,
|
||||
},
|
||||
/* board_ahci_sb600 */
|
||||
[board_ahci_sb600] =
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL |
|
||||
AHCI_HFLAG_32BIT_ONLY | AHCI_HFLAG_NO_MSI |
|
||||
AHCI_HFLAG_SECT255),
|
||||
AHCI_HFLAG_NO_MSI | AHCI_HFLAG_SECT255),
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_sb600_ops,
|
||||
},
|
||||
/* board_ahci_mv */
|
||||
[board_ahci_mv] =
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_NO_NCQ | AHCI_HFLAG_NO_MSI |
|
||||
AHCI_HFLAG_MV_PATA | AHCI_HFLAG_NO_PMP),
|
||||
|
|
@ -446,7 +447,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
|||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_ops,
|
||||
},
|
||||
/* board_ahci_sb700, for SB700 and SB800 */
|
||||
[board_ahci_sb700] = /* for SB700 and SB800 */
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_IGN_SERR_INTERNAL),
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
|
|
@ -454,7 +455,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
|||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_sb600_ops,
|
||||
},
|
||||
/* board_ahci_mcp65 */
|
||||
[board_ahci_mcp65] =
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_YES_NCQ),
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
|
|
@ -462,7 +463,7 @@ static const struct ata_port_info ahci_port_info[] = {
|
|||
.udma_mask = ATA_UDMA6,
|
||||
.port_ops = &ahci_ops,
|
||||
},
|
||||
/* board_ahci_nopmp */
|
||||
[board_ahci_nopmp] =
|
||||
{
|
||||
AHCI_HFLAGS (AHCI_HFLAG_NO_PMP),
|
||||
.flags = AHCI_FLAG_COMMON,
|
||||
|
|
@ -1140,12 +1141,12 @@ static void ahci_start_port(struct ata_port *ap)
|
|||
emp = &pp->em_priv[link->pmp];
|
||||
|
||||
/* EM Transmit bit maybe busy during init */
|
||||
for (i = 0; i < MAX_RETRY; i++) {
|
||||
for (i = 0; i < EM_MAX_RETRY; i++) {
|
||||
rc = ahci_transmit_led_message(ap,
|
||||
emp->led_state,
|
||||
4);
|
||||
if (rc == -EBUSY)
|
||||
udelay(100);
|
||||
msleep(1);
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
|
@ -1339,7 +1340,7 @@ static ssize_t ahci_transmit_led_message(struct ata_port *ap, u32 state,
|
|||
|
||||
/* get the slot number from the message */
|
||||
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
|
||||
if (pmp < MAX_SLOTS)
|
||||
if (pmp < EM_MAX_SLOTS)
|
||||
emp = &pp->em_priv[pmp];
|
||||
else
|
||||
return -EINVAL;
|
||||
|
|
@ -1407,7 +1408,7 @@ static ssize_t ahci_led_store(struct ata_port *ap, const char *buf,
|
|||
|
||||
/* get the slot number from the message */
|
||||
pmp = (state & EM_MSG_LED_PMP_SLOT) >> 8;
|
||||
if (pmp < MAX_SLOTS)
|
||||
if (pmp < EM_MAX_SLOTS)
|
||||
emp = &pp->em_priv[pmp];
|
||||
else
|
||||
return -EINVAL;
|
||||
|
|
@ -2316,9 +2317,17 @@ static int ahci_port_suspend(struct ata_port *ap, pm_message_t mesg)
|
|||
static int ahci_pci_device_suspend(struct pci_dev *pdev, pm_message_t mesg)
|
||||
{
|
||||
struct ata_host *host = dev_get_drvdata(&pdev->dev);
|
||||
struct ahci_host_priv *hpriv = host->private_data;
|
||||
void __iomem *mmio = host->iomap[AHCI_PCI_BAR];
|
||||
u32 ctl;
|
||||
|
||||
if (mesg.event & PM_EVENT_SUSPEND &&
|
||||
hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
|
||||
dev_printk(KERN_ERR, &pdev->dev,
|
||||
"BIOS update required for suspend/resume\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (mesg.event & PM_EVENT_SLEEP) {
|
||||
/* AHCI spec rev1.1 section 8.3.3:
|
||||
* Software must disable interrupts prior to requesting a
|
||||
|
|
@ -2575,6 +2584,51 @@ static void ahci_p5wdh_workaround(struct ata_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SB600 ahci controller on ASUS M2A-VM can't do 64bit DMA with older
|
||||
* BIOS. The oldest version known to be broken is 0901 and working is
|
||||
* 1501 which was released on 2007-10-26. Force 32bit DMA on anything
|
||||
* older than 1501. Please read bko#9412 for more info.
|
||||
*/
|
||||
static bool ahci_asus_m2a_vm_32bit_only(struct pci_dev *pdev)
|
||||
{
|
||||
static const struct dmi_system_id sysids[] = {
|
||||
{
|
||||
.ident = "ASUS M2A-VM",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR,
|
||||
"ASUSTeK Computer INC."),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "M2A-VM"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
const char *cutoff_mmdd = "10/26";
|
||||
const char *date;
|
||||
int year;
|
||||
|
||||
if (pdev->bus->number != 0 || pdev->devfn != PCI_DEVFN(0x12, 0) ||
|
||||
!dmi_check_system(sysids))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Argh.... both version and date are free form strings.
|
||||
* Let's hope they're using the same date format across
|
||||
* different versions.
|
||||
*/
|
||||
date = dmi_get_system_info(DMI_BIOS_DATE);
|
||||
year = dmi_get_year(DMI_BIOS_DATE);
|
||||
if (date && strlen(date) >= 10 && date[2] == '/' && date[5] == '/' &&
|
||||
(year > 2007 ||
|
||||
(year == 2007 && strncmp(date, cutoff_mmdd, 5) >= 0)))
|
||||
return false;
|
||||
|
||||
dev_printk(KERN_WARNING, &pdev->dev, "ASUS M2A-VM: BIOS too old, "
|
||||
"forcing 32bit DMA, update BIOS\n");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
|
||||
{
|
||||
static const struct dmi_system_id broken_systems[] = {
|
||||
|
|
@ -2610,6 +2664,63 @@ static bool ahci_broken_system_poweroff(struct pci_dev *pdev)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool ahci_broken_suspend(struct pci_dev *pdev)
|
||||
{
|
||||
static const struct dmi_system_id sysids[] = {
|
||||
/*
|
||||
* On HP dv[4-6] and HDX18 with earlier BIOSen, link
|
||||
* to the harddisk doesn't become online after
|
||||
* resuming from STR. Warn and fail suspend.
|
||||
*/
|
||||
{
|
||||
.ident = "dv4",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME,
|
||||
"HP Pavilion dv4 Notebook PC"),
|
||||
},
|
||||
.driver_data = "F.30", /* cutoff BIOS version */
|
||||
},
|
||||
{
|
||||
.ident = "dv5",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME,
|
||||
"HP Pavilion dv5 Notebook PC"),
|
||||
},
|
||||
.driver_data = "F.16", /* cutoff BIOS version */
|
||||
},
|
||||
{
|
||||
.ident = "dv6",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME,
|
||||
"HP Pavilion dv6 Notebook PC"),
|
||||
},
|
||||
.driver_data = "F.21", /* cutoff BIOS version */
|
||||
},
|
||||
{
|
||||
.ident = "HDX18",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME,
|
||||
"HP HDX18 Notebook PC"),
|
||||
},
|
||||
.driver_data = "F.23", /* cutoff BIOS version */
|
||||
},
|
||||
{ } /* terminate list */
|
||||
};
|
||||
const struct dmi_system_id *dmi = dmi_first_match(sysids);
|
||||
const char *ver;
|
||||
|
||||
if (!dmi || pdev->bus->number || pdev->devfn != PCI_DEVFN(0x1f, 2))
|
||||
return false;
|
||||
|
||||
ver = dmi_get_system_info(DMI_BIOS_VERSION);
|
||||
|
||||
return !ver || strcmp(ver, dmi->driver_data) < 0;
|
||||
}
|
||||
|
||||
static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
static int printed_version;
|
||||
|
|
@ -2678,6 +2789,10 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
if (board_id == board_ahci_sb700 && pdev->revision >= 0x40)
|
||||
hpriv->flags &= ~AHCI_HFLAG_IGN_SERR_INTERNAL;
|
||||
|
||||
/* apply ASUS M2A_VM quirk */
|
||||
if (ahci_asus_m2a_vm_32bit_only(pdev))
|
||||
hpriv->flags |= AHCI_HFLAG_32BIT_ONLY;
|
||||
|
||||
if (!(hpriv->flags & AHCI_HFLAG_NO_MSI))
|
||||
pci_enable_msi(pdev);
|
||||
|
||||
|
|
@ -2715,6 +2830,12 @@ static int ahci_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
"quirky BIOS, skipping spindown on poweroff\n");
|
||||
}
|
||||
|
||||
if (ahci_broken_suspend(pdev)) {
|
||||
hpriv->flags |= AHCI_HFLAG_NO_SUSPEND;
|
||||
dev_printk(KERN_WARNING, &pdev->dev,
|
||||
"BIOS update required for suspend/resume\n");
|
||||
}
|
||||
|
||||
/* CAP.NP sometimes indicate the index of the last enabled
|
||||
* port, at other times, that of the last possible port, so
|
||||
* determining the maximum port number requires looking at
|
||||
|
|
|
|||
|
|
@ -223,10 +223,8 @@ static const struct pci_device_id piix_pci_tbl[] = {
|
|||
/* ICH8 Mobile PATA Controller */
|
||||
{ 0x8086, 0x2850, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich_pata_100 },
|
||||
|
||||
/* NOTE: The following PCI ids must be kept in sync with the
|
||||
* list in drivers/pci/quirks.c.
|
||||
*/
|
||||
|
||||
/* SATA ports */
|
||||
|
||||
/* 82801EB (ICH5) */
|
||||
{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
|
||||
/* 82801EB (ICH5) */
|
||||
|
|
@ -1455,6 +1453,15 @@ static bool piix_broken_system_poweroff(struct pci_dev *pdev)
|
|||
/* PCI slot number of the controller */
|
||||
.driver_data = (void *)0x1FUL,
|
||||
},
|
||||
{
|
||||
.ident = "HP Compaq nc6000",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nc6000"),
|
||||
},
|
||||
/* PCI slot number of the controller */
|
||||
.driver_data = (void *)0x1FUL,
|
||||
},
|
||||
|
||||
{ } /* terminate list */
|
||||
};
|
||||
|
|
@ -1500,8 +1507,8 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
|||
dev_printk(KERN_DEBUG, &pdev->dev,
|
||||
"version " DRV_VERSION "\n");
|
||||
|
||||
/* no hotplugging support (FIXME) */
|
||||
if (!in_module_init)
|
||||
/* no hotplugging support for later devices (FIXME) */
|
||||
if (!in_module_init && ent->driver_data >= ich5_sata)
|
||||
return -ENODEV;
|
||||
|
||||
if (piix_broken_system_poweroff(pdev)) {
|
||||
|
|
@ -1582,6 +1589,7 @@ static int __devinit piix_init_one(struct pci_dev *pdev,
|
|||
host->ports[1]->mwdma_mask = 0;
|
||||
host->ports[1]->udma_mask = 0;
|
||||
}
|
||||
host->flags |= ATA_HOST_PARALLEL_SCAN;
|
||||
|
||||
pci_set_master(pdev);
|
||||
return ata_pci_sff_activate_host(host, ata_sff_interrupt, &piix_sht);
|
||||
|
|
|
|||
|
|
@ -5031,7 +5031,6 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
|
|||
{
|
||||
int nr_done = 0;
|
||||
u32 done_mask;
|
||||
int i;
|
||||
|
||||
done_mask = ap->qc_active ^ qc_active;
|
||||
|
||||
|
|
@ -5041,16 +5040,16 @@ int ata_qc_complete_multiple(struct ata_port *ap, u32 qc_active)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < ATA_MAX_QUEUE; i++) {
|
||||
while (done_mask) {
|
||||
struct ata_queued_cmd *qc;
|
||||
unsigned int tag = __ffs(done_mask);
|
||||
|
||||
if (!(done_mask & (1 << i)))
|
||||
continue;
|
||||
|
||||
if ((qc = ata_qc_from_tag(ap, i))) {
|
||||
qc = ata_qc_from_tag(ap, tag);
|
||||
if (qc) {
|
||||
ata_qc_complete(qc);
|
||||
nr_done++;
|
||||
}
|
||||
done_mask &= ~(1 << tag);
|
||||
}
|
||||
|
||||
return nr_done;
|
||||
|
|
|
|||
|
|
@ -1084,7 +1084,7 @@ static int atapi_drain_needed(struct request *rq)
|
|||
if (likely(!blk_pc_request(rq)))
|
||||
return 0;
|
||||
|
||||
if (!rq->data_len || (rq->cmd_flags & REQ_RW))
|
||||
if (!blk_rq_bytes(rq) || (rq->cmd_flags & REQ_RW))
|
||||
return 0;
|
||||
|
||||
return atapi_cmd_type(rq->cmd[0]) == ATAPI_MISC;
|
||||
|
|
|
|||
|
|
@ -727,17 +727,23 @@ unsigned int ata_sff_data_xfer(struct ata_device *dev, unsigned char *buf,
|
|||
else
|
||||
iowrite16_rep(data_addr, buf, words);
|
||||
|
||||
/* Transfer trailing 1 byte, if any. */
|
||||
/* Transfer trailing byte, if any. */
|
||||
if (unlikely(buflen & 0x01)) {
|
||||
__le16 align_buf[1] = { 0 };
|
||||
unsigned char *trailing_buf = buf + buflen - 1;
|
||||
unsigned char pad[2];
|
||||
|
||||
/* Point buf to the tail of buffer */
|
||||
buf += buflen - 1;
|
||||
|
||||
/*
|
||||
* Use io*16_rep() accessors here as well to avoid pointlessly
|
||||
* swapping bytes to and fro on the big endian machines...
|
||||
*/
|
||||
if (rw == READ) {
|
||||
align_buf[0] = cpu_to_le16(ioread16(data_addr));
|
||||
memcpy(trailing_buf, align_buf, 1);
|
||||
ioread16_rep(data_addr, pad, 1);
|
||||
*buf = pad[0];
|
||||
} else {
|
||||
memcpy(align_buf, trailing_buf, 1);
|
||||
iowrite16(le16_to_cpu(align_buf[0]), data_addr);
|
||||
pad[0] = *buf;
|
||||
iowrite16_rep(data_addr, pad, 1);
|
||||
}
|
||||
words++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -497,14 +497,16 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
};
|
||||
/* Revision 0x20 added DMA */
|
||||
static const struct ata_port_info info_20 = {
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
|
||||
ATA_FLAG_IGN_SIMPLEX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.port_ops = &ali_20_port_ops
|
||||
};
|
||||
/* Revision 0x20 with support logic added UDMA */
|
||||
static const struct ata_port_info info_20_udma = {
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
|
||||
ATA_FLAG_IGN_SIMPLEX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA2,
|
||||
|
|
@ -512,7 +514,8 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
};
|
||||
/* Revision 0xC2 adds UDMA66 */
|
||||
static const struct ata_port_info info_c2 = {
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
|
||||
ATA_FLAG_IGN_SIMPLEX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA4,
|
||||
|
|
@ -520,7 +523,8 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
};
|
||||
/* Revision 0xC3 is UDMA66 for now */
|
||||
static const struct ata_port_info info_c3 = {
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
|
||||
ATA_FLAG_IGN_SIMPLEX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA4,
|
||||
|
|
@ -528,7 +532,8 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
};
|
||||
/* Revision 0xC4 is UDMA100 */
|
||||
static const struct ata_port_info info_c4 = {
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_PIO_LBA48 |
|
||||
ATA_FLAG_IGN_SIMPLEX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
|
|
@ -536,7 +541,7 @@ static int ali_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
};
|
||||
/* Revision 0xC5 is UDMA133 with LBA48 DMA */
|
||||
static const struct ata_port_info info_c5 = {
|
||||
.flags = ATA_FLAG_SLAVE_POSS,
|
||||
.flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_IGN_SIMPLEX,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA6,
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include <linux/ata.h>
|
||||
|
||||
#define DRV_NAME "pata_efar"
|
||||
#define DRV_VERSION "0.4.4"
|
||||
#define DRV_VERSION "0.4.5"
|
||||
|
||||
/**
|
||||
* efar_pre_reset - Enable bits
|
||||
|
|
@ -98,18 +98,17 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
|
|||
{ 2, 1 },
|
||||
{ 2, 3 }, };
|
||||
|
||||
if (pio > 2)
|
||||
control |= 1; /* TIME1 enable */
|
||||
if (pio > 1)
|
||||
control |= 1; /* TIME */
|
||||
if (ata_pio_need_iordy(adev)) /* PIO 3/4 require IORDY */
|
||||
control |= 2; /* IE enable */
|
||||
/* Intel specifies that the PPE functionality is for disk only */
|
||||
control |= 2; /* IE */
|
||||
/* Intel specifies that the prefetch/posting is for disk only */
|
||||
if (adev->class == ATA_DEV_ATA)
|
||||
control |= 4; /* PPE enable */
|
||||
control |= 4; /* PPE */
|
||||
|
||||
pci_read_config_word(dev, idetm_port, &idetm_data);
|
||||
|
||||
/* Enable PPE, IE and TIME as appropriate */
|
||||
|
||||
/* Set PPE, IE, and TIME as appropriate */
|
||||
if (adev->devno == 0) {
|
||||
idetm_data &= 0xCCF0;
|
||||
idetm_data |= control;
|
||||
|
|
@ -129,7 +128,7 @@ static void efar_set_piomode (struct ata_port *ap, struct ata_device *adev)
|
|||
pci_write_config_byte(dev, 0x44, slave_data);
|
||||
}
|
||||
|
||||
idetm_data |= 0x4000; /* Ensure SITRE is enabled */
|
||||
idetm_data |= 0x4000; /* Ensure SITRE is set */
|
||||
pci_write_config_word(dev, idetm_port, idetm_data);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
@ -1028,6 +1029,7 @@ static __init int legacy_init_one(struct legacy_probe *probe)
|
|||
&legacy_sht);
|
||||
if (ret)
|
||||
goto fail;
|
||||
async_synchronize_full();
|
||||
ld->platform_dev = pdev;
|
||||
|
||||
/* Nothing found means we drop the port as its probably not there */
|
||||
|
|
|
|||
|
|
@ -20,13 +20,24 @@
|
|||
|
||||
/* No PIO or DMA methods needed for this device */
|
||||
|
||||
static unsigned int netcell_read_id(struct ata_device *adev,
|
||||
struct ata_taskfile *tf, u16 *id)
|
||||
{
|
||||
unsigned int err_mask = ata_do_dev_read_id(adev, tf, id);
|
||||
/* Firmware forgets to mark words 85-87 valid */
|
||||
if (err_mask == 0)
|
||||
id[ATA_ID_CSF_DEFAULT] |= 0x4000;
|
||||
return err_mask;
|
||||
}
|
||||
|
||||
static struct scsi_host_template netcell_sht = {
|
||||
ATA_BMDMA_SHT(DRV_NAME),
|
||||
};
|
||||
|
||||
static struct ata_port_operations netcell_ops = {
|
||||
.inherits = &ata_bmdma_port_ops,
|
||||
.cable_detect = ata_cable_80wire,
|
||||
.cable_detect = ata_cable_80wire,
|
||||
.read_id = netcell_read_id,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -305,8 +305,8 @@ static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance);
|
|||
static int nv_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
|
||||
static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
|
||||
|
||||
static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline);
|
||||
static int nv_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline);
|
||||
static void nv_nf2_freeze(struct ata_port *ap);
|
||||
static void nv_nf2_thaw(struct ata_port *ap);
|
||||
static void nv_ck804_freeze(struct ata_port *ap);
|
||||
|
|
@ -406,49 +406,82 @@ static struct scsi_host_template nv_swncq_sht = {
|
|||
.slave_configure = nv_swncq_slave_config,
|
||||
};
|
||||
|
||||
static struct ata_port_operations nv_common_ops = {
|
||||
/*
|
||||
* NV SATA controllers have various different problems with hardreset
|
||||
* protocol depending on the specific controller and device.
|
||||
*
|
||||
* GENERIC:
|
||||
*
|
||||
* bko11195 reports that link doesn't come online after hardreset on
|
||||
* generic nv's and there have been several other similar reports on
|
||||
* linux-ide.
|
||||
*
|
||||
* bko12351#c23 reports that warmplug on MCP61 doesn't work with
|
||||
* softreset.
|
||||
*
|
||||
* NF2/3:
|
||||
*
|
||||
* bko3352 reports nf2/3 controllers can't determine device signature
|
||||
* reliably after hardreset. The following thread reports detection
|
||||
* failure on cold boot with the standard debouncing timing.
|
||||
*
|
||||
* http://thread.gmane.org/gmane.linux.ide/34098
|
||||
*
|
||||
* bko12176 reports that hardreset fails to bring up the link during
|
||||
* boot on nf2.
|
||||
*
|
||||
* CK804:
|
||||
*
|
||||
* For initial probing after boot and hot plugging, hardreset mostly
|
||||
* works fine on CK804 but curiously, reprobing on the initial port
|
||||
* by rescanning or rmmod/insmod fails to acquire the initial D2H Reg
|
||||
* FIS in somewhat undeterministic way.
|
||||
*
|
||||
* SWNCQ:
|
||||
*
|
||||
* bko12351 reports that when SWNCQ is enabled, for hotplug to work,
|
||||
* hardreset should be used and hardreset can't report proper
|
||||
* signature, which suggests that mcp5x is closer to nf2 as long as
|
||||
* reset quirkiness is concerned.
|
||||
*
|
||||
* bko12703 reports that boot probing fails for intel SSD with
|
||||
* hardreset. Link fails to come online. Softreset works fine.
|
||||
*
|
||||
* The failures are varied but the following patterns seem true for
|
||||
* all flavors.
|
||||
*
|
||||
* - Softreset during boot always works.
|
||||
*
|
||||
* - Hardreset during boot sometimes fails to bring up the link on
|
||||
* certain comibnations and device signature acquisition is
|
||||
* unreliable.
|
||||
*
|
||||
* - Hardreset is often necessary after hotplug.
|
||||
*
|
||||
* So, preferring softreset for boot probing and error handling (as
|
||||
* hardreset might bring down the link) but using hardreset for
|
||||
* post-boot probing should work around the above issues in most
|
||||
* cases. Define nv_hardreset() which only kicks in for post-boot
|
||||
* probing and use it for all variants.
|
||||
*/
|
||||
static struct ata_port_operations nv_generic_ops = {
|
||||
.inherits = &ata_bmdma_port_ops,
|
||||
.lost_interrupt = ATA_OP_NULL,
|
||||
.scr_read = nv_scr_read,
|
||||
.scr_write = nv_scr_write,
|
||||
.hardreset = nv_hardreset,
|
||||
};
|
||||
|
||||
/* OSDL bz11195 reports that link doesn't come online after hardreset
|
||||
* on generic nv's and there have been several other similar reports
|
||||
* on linux-ide. Disable hardreset for generic nv's.
|
||||
*/
|
||||
static struct ata_port_operations nv_generic_ops = {
|
||||
.inherits = &nv_common_ops,
|
||||
.hardreset = ATA_OP_NULL,
|
||||
};
|
||||
|
||||
/* nf2 is ripe with hardreset related problems.
|
||||
*
|
||||
* kernel bz#3352 reports nf2/3 controllers can't determine device
|
||||
* signature reliably. The following thread reports detection failure
|
||||
* on cold boot with the standard debouncing timing.
|
||||
*
|
||||
* http://thread.gmane.org/gmane.linux.ide/34098
|
||||
*
|
||||
* And bz#12176 reports that hardreset simply doesn't work on nf2.
|
||||
* Give up on it and just don't do hardreset.
|
||||
*/
|
||||
static struct ata_port_operations nv_nf2_ops = {
|
||||
.inherits = &nv_generic_ops,
|
||||
.freeze = nv_nf2_freeze,
|
||||
.thaw = nv_nf2_thaw,
|
||||
};
|
||||
|
||||
/* For initial probing after boot and hot plugging, hardreset mostly
|
||||
* works fine on CK804 but curiously, reprobing on the initial port by
|
||||
* rescanning or rmmod/insmod fails to acquire the initial D2H Reg FIS
|
||||
* in somewhat undeterministic way. Use noclassify hardreset.
|
||||
*/
|
||||
static struct ata_port_operations nv_ck804_ops = {
|
||||
.inherits = &nv_common_ops,
|
||||
.inherits = &nv_generic_ops,
|
||||
.freeze = nv_ck804_freeze,
|
||||
.thaw = nv_ck804_thaw,
|
||||
.hardreset = nv_noclassify_hardreset,
|
||||
.host_stop = nv_ck804_host_stop,
|
||||
};
|
||||
|
||||
|
|
@ -476,19 +509,8 @@ static struct ata_port_operations nv_adma_ops = {
|
|||
.host_stop = nv_adma_host_stop,
|
||||
};
|
||||
|
||||
/* Kernel bz#12351 reports that when SWNCQ is enabled, for hotplug to
|
||||
* work, hardreset should be used and hardreset can't report proper
|
||||
* signature, which suggests that mcp5x is closer to nf2 as long as
|
||||
* reset quirkiness is concerned. Define separate ops for mcp5x with
|
||||
* nv_noclassify_hardreset().
|
||||
*/
|
||||
static struct ata_port_operations nv_mcp5x_ops = {
|
||||
.inherits = &nv_common_ops,
|
||||
.hardreset = nv_noclassify_hardreset,
|
||||
};
|
||||
|
||||
static struct ata_port_operations nv_swncq_ops = {
|
||||
.inherits = &nv_mcp5x_ops,
|
||||
.inherits = &nv_generic_ops,
|
||||
|
||||
.qc_defer = ata_std_qc_defer,
|
||||
.qc_prep = nv_swncq_qc_prep,
|
||||
|
|
@ -557,7 +579,7 @@ static const struct ata_port_info nv_port_info[] = {
|
|||
.pio_mask = NV_PIO_MASK,
|
||||
.mwdma_mask = NV_MWDMA_MASK,
|
||||
.udma_mask = NV_UDMA_MASK,
|
||||
.port_ops = &nv_mcp5x_ops,
|
||||
.port_ops = &nv_generic_ops,
|
||||
.private_data = NV_PI_PRIV(nv_generic_interrupt, &nv_sht),
|
||||
},
|
||||
/* SWNCQ */
|
||||
|
|
@ -1559,15 +1581,24 @@ static int nv_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nv_noclassify_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
static int nv_hardreset(struct ata_link *link, unsigned int *class,
|
||||
unsigned long deadline)
|
||||
{
|
||||
bool online;
|
||||
int rc;
|
||||
struct ata_eh_context *ehc = &link->eh_context;
|
||||
|
||||
rc = sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
|
||||
&online, NULL);
|
||||
return online ? -EAGAIN : rc;
|
||||
/* Do hardreset iff it's post-boot probing, please read the
|
||||
* comment above port ops for details.
|
||||
*/
|
||||
if (!(link->ap->pflags & ATA_PFLAG_LOADING) &&
|
||||
!ata_dev_enabled(link->device))
|
||||
sata_link_hardreset(link, sata_deb_timing_hotplug, deadline,
|
||||
NULL, NULL);
|
||||
else if (!(ehc->i.flags & ATA_EHI_QUIET))
|
||||
ata_link_printk(link, KERN_INFO,
|
||||
"nv: skipping hardreset on occupied port\n");
|
||||
|
||||
/* device signature acquisition is unreliable */
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
static void nv_nf2_freeze(struct ata_port *ap)
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ static struct scsi_host_template sil_sht = {
|
|||
};
|
||||
|
||||
static struct ata_port_operations sil_ops = {
|
||||
.inherits = &ata_bmdma_port_ops,
|
||||
.inherits = &ata_bmdma32_port_ops,
|
||||
.dev_config = sil_dev_config,
|
||||
.set_mode = sil_set_mode,
|
||||
.bmdma_setup = sil_bmdma_setup,
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ enum {
|
|||
PDC_TIMER_MASK_INT,
|
||||
};
|
||||
|
||||
#define ECC_ERASE_BUF_SZ (128 * 1024)
|
||||
|
||||
struct pdc_port_priv {
|
||||
u8 dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
|
||||
|
|
@ -1280,7 +1281,6 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
|
|||
{
|
||||
int speed, size, length;
|
||||
u32 addr, spd0, pci_status;
|
||||
u32 tmp = 0;
|
||||
u32 time_period = 0;
|
||||
u32 tcount = 0;
|
||||
u32 ticks = 0;
|
||||
|
|
@ -1395,14 +1395,17 @@ static unsigned int pdc20621_dimm_init(struct ata_host *host)
|
|||
pdc20621_i2c_read(host, PDC_DIMM0_SPD_DEV_ADDRESS,
|
||||
PDC_DIMM_SPD_TYPE, &spd0);
|
||||
if (spd0 == 0x02) {
|
||||
void *buf;
|
||||
VPRINTK("Start ECC initialization\n");
|
||||
addr = 0;
|
||||
length = size * 1024 * 1024;
|
||||
buf = kzalloc(ECC_ERASE_BUF_SZ, GFP_KERNEL);
|
||||
while (addr < length) {
|
||||
pdc20621_put_to_dimm(host, (void *) &tmp, addr,
|
||||
sizeof(u32));
|
||||
addr += sizeof(u32);
|
||||
pdc20621_put_to_dimm(host, buf, addr,
|
||||
ECC_ERASE_BUF_SZ);
|
||||
addr += ECC_ERASE_BUF_SZ;
|
||||
}
|
||||
kfree(buf);
|
||||
VPRINTK("Finish ECC initialization\n");
|
||||
}
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -700,8 +700,10 @@ int bus_add_driver(struct device_driver *drv)
|
|||
}
|
||||
|
||||
kobject_uevent(&priv->kobj, KOBJ_ADD);
|
||||
return error;
|
||||
return 0;
|
||||
out_unregister:
|
||||
kfree(drv->p);
|
||||
drv->p = NULL;
|
||||
kobject_put(&priv->kobj);
|
||||
out_put_bus:
|
||||
bus_put(bus);
|
||||
|
|
|
|||
|
|
@ -879,7 +879,7 @@ int device_add(struct device *dev)
|
|||
}
|
||||
|
||||
if (!dev_name(dev))
|
||||
goto done;
|
||||
goto name_error;
|
||||
|
||||
pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
|
||||
|
||||
|
|
@ -978,6 +978,9 @@ done:
|
|||
cleanup_device_parent(dev);
|
||||
if (parent)
|
||||
put_device(parent);
|
||||
name_error:
|
||||
kfree(dev->p);
|
||||
dev->p = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -257,6 +257,10 @@ EXPORT_SYMBOL_GPL(driver_register);
|
|||
*/
|
||||
void driver_unregister(struct device_driver *drv)
|
||||
{
|
||||
if (!drv || !drv->p) {
|
||||
WARN(1, "Unexpected driver unregister!\n");
|
||||
return;
|
||||
}
|
||||
driver_remove_groups(drv, drv->groups);
|
||||
bus_remove_driver(drv);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,6 +357,7 @@ static void dpm_power_up(pm_message_t state)
|
|||
{
|
||||
struct device *dev;
|
||||
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
list_for_each_entry(dev, &dpm_list, power.entry)
|
||||
if (dev->power.status > DPM_OFF) {
|
||||
int error;
|
||||
|
|
@ -366,6 +367,7 @@ static void dpm_power_up(pm_message_t state)
|
|||
if (error)
|
||||
pm_dev_err(dev, state, " early", error);
|
||||
}
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -614,6 +616,7 @@ int device_power_down(pm_message_t state)
|
|||
int error = 0;
|
||||
|
||||
suspend_device_irqs();
|
||||
mutex_lock(&dpm_list_mtx);
|
||||
list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
|
||||
error = suspend_device_noirq(dev, state);
|
||||
if (error) {
|
||||
|
|
@ -622,6 +625,7 @@ int device_power_down(pm_message_t state)
|
|||
}
|
||||
dev->power.status = DPM_OFF_IRQ;
|
||||
}
|
||||
mutex_unlock(&dpm_list_mtx);
|
||||
if (error)
|
||||
device_power_up(resume_event(state));
|
||||
return error;
|
||||
|
|
|
|||
|
|
@ -3321,7 +3321,7 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_
|
|||
DAC960_Command_T *Command;
|
||||
|
||||
while(1) {
|
||||
Request = elv_next_request(req_q);
|
||||
Request = blk_peek_request(req_q);
|
||||
if (!Request)
|
||||
return 1;
|
||||
|
||||
|
|
@ -3338,10 +3338,10 @@ static int DAC960_process_queue(DAC960_Controller_T *Controller, struct request_
|
|||
}
|
||||
Command->Completion = Request->end_io_data;
|
||||
Command->LogicalDriveNumber = (long)Request->rq_disk->private_data;
|
||||
Command->BlockNumber = Request->sector;
|
||||
Command->BlockCount = Request->nr_sectors;
|
||||
Command->BlockNumber = blk_rq_pos(Request);
|
||||
Command->BlockCount = blk_rq_sectors(Request);
|
||||
Command->Request = Request;
|
||||
blkdev_dequeue_request(Request);
|
||||
blk_start_request(Request);
|
||||
Command->SegmentCount = blk_rq_map_sg(req_q,
|
||||
Command->Request, Command->cmd_sglist);
|
||||
/* pci_map_sg MAY change the value of SegCount */
|
||||
|
|
@ -3431,7 +3431,7 @@ static void DAC960_queue_partial_rw(DAC960_Command_T *Command)
|
|||
* successfully as possible.
|
||||
*/
|
||||
Command->SegmentCount = 1;
|
||||
Command->BlockNumber = Request->sector;
|
||||
Command->BlockNumber = blk_rq_pos(Request);
|
||||
Command->BlockCount = 1;
|
||||
DAC960_QueueReadWriteCommand(Command);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -412,7 +412,7 @@ config ATA_OVER_ETH
|
|||
|
||||
config MG_DISK
|
||||
tristate "mGine mflash, gflash support"
|
||||
depends on ARM && ATA && GPIOLIB
|
||||
depends on ARM && GPIOLIB
|
||||
help
|
||||
mGine mFlash(gFlash) block device driver
|
||||
|
||||
|
|
|
|||
|
|
@ -112,8 +112,6 @@ module_param(fd_def_df0, ulong, 0);
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct request_queue *floppy_queue;
|
||||
#define QUEUE (floppy_queue)
|
||||
#define CURRENT elv_next_request(floppy_queue)
|
||||
|
||||
/*
|
||||
* Macros
|
||||
|
|
@ -1335,64 +1333,60 @@ static int get_track(int drive, int track)
|
|||
|
||||
static void redo_fd_request(void)
|
||||
{
|
||||
struct request *rq;
|
||||
unsigned int cnt, block, track, sector;
|
||||
int drive;
|
||||
struct amiga_floppy_struct *floppy;
|
||||
char *data;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
repeat:
|
||||
if (!CURRENT) {
|
||||
next_req:
|
||||
rq = blk_fetch_request(floppy_queue);
|
||||
if (!rq) {
|
||||
/* Nothing left to do */
|
||||
return;
|
||||
}
|
||||
|
||||
floppy = CURRENT->rq_disk->private_data;
|
||||
floppy = rq->rq_disk->private_data;
|
||||
drive = floppy - unit;
|
||||
|
||||
next_segment:
|
||||
/* Here someone could investigate to be more efficient */
|
||||
for (cnt = 0; cnt < CURRENT->current_nr_sectors; cnt++) {
|
||||
for (cnt = 0, err = 0; cnt < blk_rq_cur_sectors(rq); cnt++) {
|
||||
#ifdef DEBUG
|
||||
printk("fd: sector %ld + %d requested for %s\n",
|
||||
CURRENT->sector,cnt,
|
||||
(rq_data_dir(CURRENT) == READ) ? "read" : "write");
|
||||
blk_rq_pos(rq), cnt,
|
||||
(rq_data_dir(rq) == READ) ? "read" : "write");
|
||||
#endif
|
||||
block = CURRENT->sector + cnt;
|
||||
block = blk_rq_pos(rq) + cnt;
|
||||
if ((int)block > floppy->blocks) {
|
||||
end_request(CURRENT, 0);
|
||||
goto repeat;
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
track = block / (floppy->dtype->sects * floppy->type->sect_mult);
|
||||
sector = block % (floppy->dtype->sects * floppy->type->sect_mult);
|
||||
data = CURRENT->buffer + 512 * cnt;
|
||||
data = rq->buffer + 512 * cnt;
|
||||
#ifdef DEBUG
|
||||
printk("access to track %d, sector %d, with buffer at "
|
||||
"0x%08lx\n", track, sector, data);
|
||||
#endif
|
||||
|
||||
if ((rq_data_dir(CURRENT) != READ) && (rq_data_dir(CURRENT) != WRITE)) {
|
||||
printk(KERN_WARNING "do_fd_request: unknown command\n");
|
||||
end_request(CURRENT, 0);
|
||||
goto repeat;
|
||||
}
|
||||
if (get_track(drive, track) == -1) {
|
||||
end_request(CURRENT, 0);
|
||||
goto repeat;
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (rq_data_dir(CURRENT)) {
|
||||
case READ:
|
||||
if (rq_data_dir(rq) == READ) {
|
||||
memcpy(data, floppy->trackbuf + sector * 512, 512);
|
||||
break;
|
||||
|
||||
case WRITE:
|
||||
} else {
|
||||
memcpy(floppy->trackbuf + sector * 512, data, 512);
|
||||
|
||||
/* keep the drive spinning while writes are scheduled */
|
||||
if (!fd_motor_on(drive)) {
|
||||
end_request(CURRENT, 0);
|
||||
goto repeat;
|
||||
err = -EIO;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* setup a callback to write the track buffer
|
||||
|
|
@ -1404,14 +1398,12 @@ static void redo_fd_request(void)
|
|||
/* reset the timer */
|
||||
mod_timer (flush_track_timer + drive, jiffies + 1);
|
||||
local_irq_restore(flags);
|
||||
break;
|
||||
}
|
||||
}
|
||||
CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
|
||||
CURRENT->sector += CURRENT->current_nr_sectors;
|
||||
|
||||
end_request(CURRENT, 1);
|
||||
goto repeat;
|
||||
if (__blk_end_request_cur(rq, err))
|
||||
goto next_segment;
|
||||
goto next_req;
|
||||
}
|
||||
|
||||
static void do_fd_request(struct request_queue * q)
|
||||
|
|
|
|||
|
|
@ -79,9 +79,7 @@
|
|||
#undef DEBUG
|
||||
|
||||
static struct request_queue *floppy_queue;
|
||||
|
||||
#define QUEUE (floppy_queue)
|
||||
#define CURRENT elv_next_request(floppy_queue)
|
||||
static struct request *fd_request;
|
||||
|
||||
/* Disk types: DD, HD, ED */
|
||||
static struct atari_disk_type {
|
||||
|
|
@ -376,6 +374,12 @@ static DEFINE_TIMER(readtrack_timer, fd_readtrack_check, 0, 0);
|
|||
static DEFINE_TIMER(timeout_timer, fd_times_out, 0, 0);
|
||||
static DEFINE_TIMER(fd_timer, check_change, 0, 0);
|
||||
|
||||
static void fd_end_request_cur(int err)
|
||||
{
|
||||
if (!__blk_end_request_cur(fd_request, err))
|
||||
fd_request = NULL;
|
||||
}
|
||||
|
||||
static inline void start_motor_off_timer(void)
|
||||
{
|
||||
mod_timer(&motor_off_timer, jiffies + FD_MOTOR_OFF_DELAY);
|
||||
|
|
@ -606,15 +610,15 @@ static void fd_error( void )
|
|||
return;
|
||||
}
|
||||
|
||||
if (!CURRENT)
|
||||
if (!fd_request)
|
||||
return;
|
||||
|
||||
CURRENT->errors++;
|
||||
if (CURRENT->errors >= MAX_ERRORS) {
|
||||
fd_request->errors++;
|
||||
if (fd_request->errors >= MAX_ERRORS) {
|
||||
printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
|
||||
end_request(CURRENT, 0);
|
||||
fd_end_request_cur(-EIO);
|
||||
}
|
||||
else if (CURRENT->errors == RECALIBRATE_ERRORS) {
|
||||
else if (fd_request->errors == RECALIBRATE_ERRORS) {
|
||||
printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
|
||||
if (SelectedDrive != -1)
|
||||
SUD.track = -1;
|
||||
|
|
@ -725,16 +729,14 @@ static void do_fd_action( int drive )
|
|||
if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
|
||||
if (ReqCmd == READ) {
|
||||
copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
|
||||
if (++ReqCnt < CURRENT->current_nr_sectors) {
|
||||
if (++ReqCnt < blk_rq_cur_sectors(fd_request)) {
|
||||
/* read next sector */
|
||||
setup_req_params( drive );
|
||||
goto repeat;
|
||||
}
|
||||
else {
|
||||
/* all sectors finished */
|
||||
CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
|
||||
CURRENT->sector += CURRENT->current_nr_sectors;
|
||||
end_request(CURRENT, 1);
|
||||
fd_end_request_cur(0);
|
||||
redo_fd_request();
|
||||
return;
|
||||
}
|
||||
|
|
@ -1132,16 +1134,14 @@ static void fd_rwsec_done1(int status)
|
|||
}
|
||||
}
|
||||
|
||||
if (++ReqCnt < CURRENT->current_nr_sectors) {
|
||||
if (++ReqCnt < blk_rq_cur_sectors(fd_request)) {
|
||||
/* read next sector */
|
||||
setup_req_params( SelectedDrive );
|
||||
do_fd_action( SelectedDrive );
|
||||
}
|
||||
else {
|
||||
/* all sectors finished */
|
||||
CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
|
||||
CURRENT->sector += CURRENT->current_nr_sectors;
|
||||
end_request(CURRENT, 1);
|
||||
fd_end_request_cur(0);
|
||||
redo_fd_request();
|
||||
}
|
||||
return;
|
||||
|
|
@ -1382,7 +1382,7 @@ static void setup_req_params( int drive )
|
|||
ReqData = ReqBuffer + 512 * ReqCnt;
|
||||
|
||||
if (UseTrackbuffer)
|
||||
read_track = (ReqCmd == READ && CURRENT->errors == 0);
|
||||
read_track = (ReqCmd == READ && fd_request->errors == 0);
|
||||
else
|
||||
read_track = 0;
|
||||
|
||||
|
|
@ -1396,25 +1396,27 @@ static void redo_fd_request(void)
|
|||
int drive, type;
|
||||
struct atari_floppy_struct *floppy;
|
||||
|
||||
DPRINT(("redo_fd_request: CURRENT=%p dev=%s CURRENT->sector=%ld\n",
|
||||
CURRENT, CURRENT ? CURRENT->rq_disk->disk_name : "",
|
||||
CURRENT ? CURRENT->sector : 0 ));
|
||||
DPRINT(("redo_fd_request: fd_request=%p dev=%s fd_request->sector=%ld\n",
|
||||
fd_request, fd_request ? fd_request->rq_disk->disk_name : "",
|
||||
fd_request ? blk_rq_pos(fd_request) : 0 ));
|
||||
|
||||
IsFormatting = 0;
|
||||
|
||||
repeat:
|
||||
if (!fd_request) {
|
||||
fd_request = blk_fetch_request(floppy_queue);
|
||||
if (!fd_request)
|
||||
goto the_end;
|
||||
}
|
||||
|
||||
if (!CURRENT)
|
||||
goto the_end;
|
||||
|
||||
floppy = CURRENT->rq_disk->private_data;
|
||||
floppy = fd_request->rq_disk->private_data;
|
||||
drive = floppy - unit;
|
||||
type = floppy->type;
|
||||
|
||||
if (!UD.connected) {
|
||||
/* drive not connected */
|
||||
printk(KERN_ERR "Unknown Device: fd%d\n", drive );
|
||||
end_request(CURRENT, 0);
|
||||
fd_end_request_cur(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
|
@ -1430,12 +1432,12 @@ repeat:
|
|||
/* user supplied disk type */
|
||||
if (--type >= NUM_DISK_MINORS) {
|
||||
printk(KERN_WARNING "fd%d: invalid disk format", drive );
|
||||
end_request(CURRENT, 0);
|
||||
fd_end_request_cur(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
if (minor2disktype[type].drive_types > DriveType) {
|
||||
printk(KERN_WARNING "fd%d: unsupported disk format", drive );
|
||||
end_request(CURRENT, 0);
|
||||
fd_end_request_cur(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
type = minor2disktype[type].index;
|
||||
|
|
@ -1444,8 +1446,8 @@ repeat:
|
|||
UD.autoprobe = 0;
|
||||
}
|
||||
|
||||
if (CURRENT->sector + 1 > UDT->blocks) {
|
||||
end_request(CURRENT, 0);
|
||||
if (blk_rq_pos(fd_request) + 1 > UDT->blocks) {
|
||||
fd_end_request_cur(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
|
@ -1453,9 +1455,9 @@ repeat:
|
|||
del_timer( &motor_off_timer );
|
||||
|
||||
ReqCnt = 0;
|
||||
ReqCmd = rq_data_dir(CURRENT);
|
||||
ReqBlock = CURRENT->sector;
|
||||
ReqBuffer = CURRENT->buffer;
|
||||
ReqCmd = rq_data_dir(fd_request);
|
||||
ReqBlock = blk_rq_pos(fd_request);
|
||||
ReqBuffer = fd_request->buffer;
|
||||
setup_req_params( drive );
|
||||
do_fd_action( drive );
|
||||
|
||||
|
|
|
|||
|
|
@ -407,12 +407,7 @@ static int __init ramdisk_size(char *str)
|
|||
rd_size = simple_strtol(str, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
static int __init ramdisk_size2(char *str)
|
||||
{
|
||||
return ramdisk_size(str);
|
||||
}
|
||||
__setup("ramdisk=", ramdisk_size);
|
||||
__setup("ramdisk_size=", ramdisk_size2);
|
||||
__setup("ramdisk_size=", ramdisk_size);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,11 @@
|
|||
|
||||
#define IO_OK 0
|
||||
#define IO_ERROR 1
|
||||
#define IO_NEEDS_RETRY 3
|
||||
|
||||
#define VENDOR_LEN 8
|
||||
#define MODEL_LEN 16
|
||||
#define REV_LEN 4
|
||||
|
||||
struct ctlr_info;
|
||||
typedef struct ctlr_info ctlr_info_t;
|
||||
|
|
@ -34,23 +39,20 @@ typedef struct _drive_info_struct
|
|||
int cylinders;
|
||||
int raid_level; /* set to -1 to indicate that
|
||||
* the drive is not in use/configured
|
||||
*/
|
||||
int busy_configuring; /*This is set when the drive is being removed
|
||||
*to prevent it from being opened or it's queue
|
||||
*from being started.
|
||||
*/
|
||||
__u8 serial_no[16]; /* from inquiry page 0x83, */
|
||||
/* not necc. null terminated. */
|
||||
*/
|
||||
int busy_configuring; /* This is set when a drive is being removed
|
||||
* to prevent it from being opened or it's
|
||||
* queue from being started.
|
||||
*/
|
||||
struct device dev;
|
||||
__u8 serial_no[16]; /* from inquiry page 0x83,
|
||||
* not necc. null terminated.
|
||||
*/
|
||||
char vendor[VENDOR_LEN + 1]; /* SCSI vendor string */
|
||||
char model[MODEL_LEN + 1]; /* SCSI model string */
|
||||
char rev[REV_LEN + 1]; /* SCSI revision string */
|
||||
} drive_info_struct;
|
||||
|
||||
#ifdef CONFIG_CISS_SCSI_TAPE
|
||||
|
||||
struct sendcmd_reject_list {
|
||||
int ncompletions;
|
||||
unsigned long *complete; /* array of NR_CMDS tags */
|
||||
};
|
||||
|
||||
#endif
|
||||
struct ctlr_info
|
||||
{
|
||||
int ctlr;
|
||||
|
|
@ -118,11 +120,11 @@ struct ctlr_info
|
|||
void *scsi_ctlr; /* ptr to structure containing scsi related stuff */
|
||||
/* list of block side commands the scsi error handling sucked up */
|
||||
/* and saved for later processing */
|
||||
struct sendcmd_reject_list scsi_rejects;
|
||||
#endif
|
||||
unsigned char alive;
|
||||
struct completion *rescan_wait;
|
||||
struct task_struct *cciss_scan_thread;
|
||||
struct device dev;
|
||||
};
|
||||
|
||||
/* Defining the diffent access_menthods */
|
||||
|
|
|
|||
|
|
@ -217,6 +217,8 @@ typedef union _LUNAddr_struct {
|
|||
LogDevAddr_struct LogDev;
|
||||
} LUNAddr_struct;
|
||||
|
||||
#define CTLR_LUNID "\0\0\0\0\0\0\0\0"
|
||||
|
||||
typedef struct _CommandListHeader_struct {
|
||||
BYTE ReplyQueue;
|
||||
BYTE SGList;
|
||||
|
|
|
|||
|
|
@ -44,20 +44,13 @@
|
|||
#define CCISS_ABORT_MSG 0x00
|
||||
#define CCISS_RESET_MSG 0x01
|
||||
|
||||
/* some prototypes... */
|
||||
static int sendcmd(
|
||||
__u8 cmd,
|
||||
int ctlr,
|
||||
void *buff,
|
||||
size_t size,
|
||||
unsigned int use_unit_num, /* 0: address the controller,
|
||||
1: address logical volume log_unit,
|
||||
2: address is in scsi3addr */
|
||||
unsigned int log_unit,
|
||||
__u8 page_code,
|
||||
unsigned char *scsi3addr,
|
||||
static int fill_cmd(CommandList_struct *c, __u8 cmd, int ctlr, void *buff,
|
||||
size_t size,
|
||||
__u8 page_code, unsigned char *scsi3addr,
|
||||
int cmd_type);
|
||||
|
||||
static CommandList_struct *cmd_alloc(ctlr_info_t *h, int get_from_pool);
|
||||
static void cmd_free(ctlr_info_t *h, CommandList_struct *c, int got_from_pool);
|
||||
|
||||
static int cciss_scsi_proc_info(
|
||||
struct Scsi_Host *sh,
|
||||
|
|
@ -1575,6 +1568,75 @@ cciss_seq_tape_report(struct seq_file *seq, int ctlr)
|
|||
CPQ_TAPE_UNLOCK(ctlr, flags);
|
||||
}
|
||||
|
||||
static int wait_for_device_to_become_ready(ctlr_info_t *h,
|
||||
unsigned char lunaddr[])
|
||||
{
|
||||
int rc;
|
||||
int count = 0;
|
||||
int waittime = HZ;
|
||||
CommandList_struct *c;
|
||||
|
||||
c = cmd_alloc(h, 1);
|
||||
if (!c) {
|
||||
printk(KERN_WARNING "cciss%d: out of memory in "
|
||||
"wait_for_device_to_become_ready.\n", h->ctlr);
|
||||
return IO_ERROR;
|
||||
}
|
||||
|
||||
/* Send test unit ready until device ready, or give up. */
|
||||
while (count < 20) {
|
||||
|
||||
/* Wait for a bit. do this first, because if we send
|
||||
* the TUR right away, the reset will just abort it.
|
||||
*/
|
||||
schedule_timeout_uninterruptible(waittime);
|
||||
count++;
|
||||
|
||||
/* Increase wait time with each try, up to a point. */
|
||||
if (waittime < (HZ * 30))
|
||||
waittime = waittime * 2;
|
||||
|
||||
/* Send the Test Unit Ready */
|
||||
rc = fill_cmd(c, TEST_UNIT_READY, h->ctlr, NULL, 0, 0,
|
||||
lunaddr, TYPE_CMD);
|
||||
if (rc == 0)
|
||||
rc = sendcmd_withirq_core(h, c, 0);
|
||||
|
||||
(void) process_sendcmd_error(h, c);
|
||||
|
||||
if (rc != 0)
|
||||
goto retry_tur;
|
||||
|
||||
if (c->err_info->CommandStatus == CMD_SUCCESS)
|
||||
break;
|
||||
|
||||
if (c->err_info->CommandStatus == CMD_TARGET_STATUS &&
|
||||
c->err_info->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
|
||||
if (c->err_info->SenseInfo[2] == NO_SENSE)
|
||||
break;
|
||||
if (c->err_info->SenseInfo[2] == UNIT_ATTENTION) {
|
||||
unsigned char asc;
|
||||
asc = c->err_info->SenseInfo[12];
|
||||
check_for_unit_attention(h, c);
|
||||
if (asc == POWER_OR_RESET)
|
||||
break;
|
||||
}
|
||||
}
|
||||
retry_tur:
|
||||
printk(KERN_WARNING "cciss%d: Waiting %d secs "
|
||||
"for device to become ready.\n",
|
||||
h->ctlr, waittime / HZ);
|
||||
rc = 1; /* device not ready. */
|
||||
}
|
||||
|
||||
if (rc)
|
||||
printk("cciss%d: giving up on device.\n", h->ctlr);
|
||||
else
|
||||
printk(KERN_WARNING "cciss%d: device is ready.\n", h->ctlr);
|
||||
|
||||
cmd_free(h, c, 1);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Need at least one of these error handlers to keep ../scsi/hosts.c from
|
||||
* complaining. Doing a host- or bus-reset can't do anything good here.
|
||||
|
|
@ -1591,6 +1653,7 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
|
|||
{
|
||||
int rc;
|
||||
CommandList_struct *cmd_in_trouble;
|
||||
unsigned char lunaddr[8];
|
||||
ctlr_info_t **c;
|
||||
int ctlr;
|
||||
|
||||
|
|
@ -1600,19 +1663,15 @@ static int cciss_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
|
|||
return FAILED;
|
||||
ctlr = (*c)->ctlr;
|
||||
printk(KERN_WARNING "cciss%d: resetting tape drive or medium changer.\n", ctlr);
|
||||
|
||||
/* find the command that's giving us trouble */
|
||||
cmd_in_trouble = (CommandList_struct *) scsicmd->host_scribble;
|
||||
if (cmd_in_trouble == NULL) { /* paranoia */
|
||||
if (cmd_in_trouble == NULL) /* paranoia */
|
||||
return FAILED;
|
||||
}
|
||||
memcpy(lunaddr, &cmd_in_trouble->Header.LUN.LunAddrBytes[0], 8);
|
||||
/* send a reset to the SCSI LUN which the command was sent to */
|
||||
rc = sendcmd(CCISS_RESET_MSG, ctlr, NULL, 0, 2, 0, 0,
|
||||
(unsigned char *) &cmd_in_trouble->Header.LUN.LunAddrBytes[0],
|
||||
rc = sendcmd_withirq(CCISS_RESET_MSG, ctlr, NULL, 0, 0, lunaddr,
|
||||
TYPE_MSG);
|
||||
/* sendcmd turned off interrupts on the board, turn 'em back on. */
|
||||
(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
|
||||
if (rc == 0)
|
||||
if (rc == 0 && wait_for_device_to_become_ready(*c, lunaddr) == 0)
|
||||
return SUCCESS;
|
||||
printk(KERN_WARNING "cciss%d: resetting device failed.\n", ctlr);
|
||||
return FAILED;
|
||||
|
|
@ -1622,6 +1681,7 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
|
|||
{
|
||||
int rc;
|
||||
CommandList_struct *cmd_to_abort;
|
||||
unsigned char lunaddr[8];
|
||||
ctlr_info_t **c;
|
||||
int ctlr;
|
||||
|
||||
|
|
@ -1636,12 +1696,9 @@ static int cciss_eh_abort_handler(struct scsi_cmnd *scsicmd)
|
|||
cmd_to_abort = (CommandList_struct *) scsicmd->host_scribble;
|
||||
if (cmd_to_abort == NULL) /* paranoia */
|
||||
return FAILED;
|
||||
rc = sendcmd(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag,
|
||||
0, 2, 0, 0,
|
||||
(unsigned char *) &cmd_to_abort->Header.LUN.LunAddrBytes[0],
|
||||
TYPE_MSG);
|
||||
/* sendcmd turned off interrupts on the board, turn 'em back on. */
|
||||
(*c)->access.set_intr_mask(*c, CCISS_INTR_ON);
|
||||
memcpy(lunaddr, &cmd_to_abort->Header.LUN.LunAddrBytes[0], 8);
|
||||
rc = sendcmd_withirq(CCISS_ABORT_MSG, ctlr, &cmd_to_abort->Header.Tag,
|
||||
0, 0, lunaddr, TYPE_MSG);
|
||||
if (rc == 0)
|
||||
return SUCCESS;
|
||||
return FAILED;
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ static int __init cpqarray_register_ctlr( int i, struct pci_dev *pdev)
|
|||
disk->fops = &ida_fops;
|
||||
if (j && !drv->nr_blks)
|
||||
continue;
|
||||
blk_queue_hardsect_size(hba[i]->queue, drv->blk_size);
|
||||
blk_queue_logical_block_size(hba[i]->queue, drv->blk_size);
|
||||
set_capacity(disk, drv->nr_blks);
|
||||
disk->queue = hba[i]->queue;
|
||||
disk->private_data = drv;
|
||||
|
|
@ -903,7 +903,7 @@ static void do_ida_request(struct request_queue *q)
|
|||
goto startio;
|
||||
|
||||
queue_next:
|
||||
creq = elv_next_request(q);
|
||||
creq = blk_peek_request(q);
|
||||
if (!creq)
|
||||
goto startio;
|
||||
|
||||
|
|
@ -912,17 +912,18 @@ queue_next:
|
|||
if ((c = cmd_alloc(h,1)) == NULL)
|
||||
goto startio;
|
||||
|
||||
blkdev_dequeue_request(creq);
|
||||
blk_start_request(creq);
|
||||
|
||||
c->ctlr = h->ctlr;
|
||||
c->hdr.unit = (drv_info_t *)(creq->rq_disk->private_data) - h->drv;
|
||||
c->hdr.size = sizeof(rblk_t) >> 2;
|
||||
c->size += sizeof(rblk_t);
|
||||
|
||||
c->req.hdr.blk = creq->sector;
|
||||
c->req.hdr.blk = blk_rq_pos(creq);
|
||||
c->rq = creq;
|
||||
DBGPX(
|
||||
printk("sector=%d, nr_sectors=%d\n", creq->sector, creq->nr_sectors);
|
||||
printk("sector=%d, nr_sectors=%u\n",
|
||||
blk_rq_pos(creq), blk_rq_sectors(creq));
|
||||
);
|
||||
sg_init_table(tmp_sg, SG_MAX);
|
||||
seg = blk_rq_map_sg(q, creq, tmp_sg);
|
||||
|
|
@ -940,9 +941,9 @@ DBGPX(
|
|||
tmp_sg[i].offset,
|
||||
tmp_sg[i].length, dir);
|
||||
}
|
||||
DBGPX( printk("Submitting %d sectors in %d segments\n", creq->nr_sectors, seg); );
|
||||
DBGPX( printk("Submitting %u sectors in %d segments\n", blk_rq_sectors(creq), seg); );
|
||||
c->req.hdr.sg_cnt = seg;
|
||||
c->req.hdr.blk_cnt = creq->nr_sectors;
|
||||
c->req.hdr.blk_cnt = blk_rq_sectors(creq);
|
||||
c->req.hdr.cmd = (rq_data_dir(creq) == READ) ? IDA_READ : IDA_WRITE;
|
||||
c->type = CMD_RWREQ;
|
||||
|
||||
|
|
@ -1024,8 +1025,7 @@ static inline void complete_command(cmdlist_t *cmd, int timeout)
|
|||
cmd->req.sg[i].size, ddir);
|
||||
|
||||
DBGPX(printk("Done with %p\n", rq););
|
||||
if (__blk_end_request(rq, error, blk_rq_bytes(rq)))
|
||||
BUG();
|
||||
__blk_end_request_all(rq, error);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1546,7 +1546,7 @@ static int revalidate_allvol(ctlr_info_t *host)
|
|||
drv_info_t *drv = &host->drv[i];
|
||||
if (i && !drv->nr_blks)
|
||||
continue;
|
||||
blk_queue_hardsect_size(host->queue, drv->blk_size);
|
||||
blk_queue_logical_block_size(host->queue, drv->blk_size);
|
||||
set_capacity(disk, drv->nr_blks);
|
||||
disk->queue = host->queue;
|
||||
disk->private_data = drv;
|
||||
|
|
|
|||
|
|
@ -931,7 +931,7 @@ static inline void unlock_fdc(void)
|
|||
del_timer(&fd_timeout);
|
||||
cont = NULL;
|
||||
clear_bit(0, &fdc_busy);
|
||||
if (elv_next_request(floppy_queue))
|
||||
if (current_req || blk_peek_request(floppy_queue))
|
||||
do_fd_request(floppy_queue);
|
||||
spin_unlock_irqrestore(&floppy_lock, flags);
|
||||
wake_up(&fdc_wait);
|
||||
|
|
@ -2303,7 +2303,7 @@ static void floppy_end_request(struct request *req, int error)
|
|||
|
||||
/* current_count_sectors can be zero if transfer failed */
|
||||
if (error)
|
||||
nr_sectors = req->current_nr_sectors;
|
||||
nr_sectors = blk_rq_cur_sectors(req);
|
||||
if (__blk_end_request(req, error, nr_sectors << 9))
|
||||
return;
|
||||
|
||||
|
|
@ -2332,7 +2332,7 @@ static void request_done(int uptodate)
|
|||
if (uptodate) {
|
||||
/* maintain values for invalidation on geometry
|
||||
* change */
|
||||
block = current_count_sectors + req->sector;
|
||||
block = current_count_sectors + blk_rq_pos(req);
|
||||
INFBOUND(DRS->maxblock, block);
|
||||
if (block > _floppy->sect)
|
||||
DRS->maxtrack = 1;
|
||||
|
|
@ -2346,10 +2346,10 @@ static void request_done(int uptodate)
|
|||
/* record write error information */
|
||||
DRWE->write_errors++;
|
||||
if (DRWE->write_errors == 1) {
|
||||
DRWE->first_error_sector = req->sector;
|
||||
DRWE->first_error_sector = blk_rq_pos(req);
|
||||
DRWE->first_error_generation = DRS->generation;
|
||||
}
|
||||
DRWE->last_error_sector = req->sector;
|
||||
DRWE->last_error_sector = blk_rq_pos(req);
|
||||
DRWE->last_error_generation = DRS->generation;
|
||||
}
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
|
|
@ -2503,24 +2503,23 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
|
|||
|
||||
max_sector = transfer_size(ssize,
|
||||
min(max_sector, max_sector_2),
|
||||
current_req->nr_sectors);
|
||||
blk_rq_sectors(current_req));
|
||||
|
||||
if (current_count_sectors <= 0 && CT(COMMAND) == FD_WRITE &&
|
||||
buffer_max > fsector_t + current_req->nr_sectors)
|
||||
buffer_max > fsector_t + blk_rq_sectors(current_req))
|
||||
current_count_sectors = min_t(int, buffer_max - fsector_t,
|
||||
current_req->nr_sectors);
|
||||
blk_rq_sectors(current_req));
|
||||
|
||||
remaining = current_count_sectors << 9;
|
||||
#ifdef FLOPPY_SANITY_CHECK
|
||||
if ((remaining >> 9) > current_req->nr_sectors &&
|
||||
CT(COMMAND) == FD_WRITE) {
|
||||
if (remaining > blk_rq_bytes(current_req) && CT(COMMAND) == FD_WRITE) {
|
||||
DPRINT("in copy buffer\n");
|
||||
printk("current_count_sectors=%ld\n", current_count_sectors);
|
||||
printk("remaining=%d\n", remaining >> 9);
|
||||
printk("current_req->nr_sectors=%ld\n",
|
||||
current_req->nr_sectors);
|
||||
printk("current_req->nr_sectors=%u\n",
|
||||
blk_rq_sectors(current_req));
|
||||
printk("current_req->current_nr_sectors=%u\n",
|
||||
current_req->current_nr_sectors);
|
||||
blk_rq_cur_sectors(current_req));
|
||||
printk("max_sector=%d\n", max_sector);
|
||||
printk("ssize=%d\n", ssize);
|
||||
}
|
||||
|
|
@ -2530,7 +2529,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
|
|||
|
||||
dma_buffer = floppy_track_buffer + ((fsector_t - buffer_min) << 9);
|
||||
|
||||
size = current_req->current_nr_sectors << 9;
|
||||
size = blk_rq_cur_bytes(current_req);
|
||||
|
||||
rq_for_each_segment(bv, current_req, iter) {
|
||||
if (!remaining)
|
||||
|
|
@ -2648,10 +2647,10 @@ static int make_raw_rw_request(void)
|
|||
|
||||
max_sector = _floppy->sect * _floppy->head;
|
||||
|
||||
TRACK = (int)current_req->sector / max_sector;
|
||||
fsector_t = (int)current_req->sector % max_sector;
|
||||
TRACK = (int)blk_rq_pos(current_req) / max_sector;
|
||||
fsector_t = (int)blk_rq_pos(current_req) % max_sector;
|
||||
if (_floppy->track && TRACK >= _floppy->track) {
|
||||
if (current_req->current_nr_sectors & 1) {
|
||||
if (blk_rq_cur_sectors(current_req) & 1) {
|
||||
current_count_sectors = 1;
|
||||
return 1;
|
||||
} else
|
||||
|
|
@ -2669,7 +2668,7 @@ static int make_raw_rw_request(void)
|
|||
if (fsector_t >= max_sector) {
|
||||
current_count_sectors =
|
||||
min_t(int, _floppy->sect - fsector_t,
|
||||
current_req->nr_sectors);
|
||||
blk_rq_sectors(current_req));
|
||||
return 1;
|
||||
}
|
||||
SIZECODE = 2;
|
||||
|
|
@ -2720,7 +2719,7 @@ static int make_raw_rw_request(void)
|
|||
|
||||
in_sector_offset = (fsector_t % _floppy->sect) % ssize;
|
||||
aligned_sector_t = fsector_t - in_sector_offset;
|
||||
max_size = current_req->nr_sectors;
|
||||
max_size = blk_rq_sectors(current_req);
|
||||
if ((raw_cmd->track == buffer_track) &&
|
||||
(current_drive == buffer_drive) &&
|
||||
(fsector_t >= buffer_min) && (fsector_t < buffer_max)) {
|
||||
|
|
@ -2729,10 +2728,10 @@ static int make_raw_rw_request(void)
|
|||
copy_buffer(1, max_sector, buffer_max);
|
||||
return 1;
|
||||
}
|
||||
} else if (in_sector_offset || current_req->nr_sectors < ssize) {
|
||||
} else if (in_sector_offset || blk_rq_sectors(current_req) < ssize) {
|
||||
if (CT(COMMAND) == FD_WRITE) {
|
||||
if (fsector_t + current_req->nr_sectors > ssize &&
|
||||
fsector_t + current_req->nr_sectors < ssize + ssize)
|
||||
if (fsector_t + blk_rq_sectors(current_req) > ssize &&
|
||||
fsector_t + blk_rq_sectors(current_req) < ssize + ssize)
|
||||
max_size = ssize + ssize;
|
||||
else
|
||||
max_size = ssize;
|
||||
|
|
@ -2776,7 +2775,7 @@ static int make_raw_rw_request(void)
|
|||
(indirect * 2 > direct * 3 &&
|
||||
*errors < DP->max_errors.read_track && ((!probing
|
||||
|| (DP->read_track & (1 << DRS->probed_format)))))) {
|
||||
max_size = current_req->nr_sectors;
|
||||
max_size = blk_rq_sectors(current_req);
|
||||
} else {
|
||||
raw_cmd->kernel_data = current_req->buffer;
|
||||
raw_cmd->length = current_count_sectors << 9;
|
||||
|
|
@ -2801,7 +2800,7 @@ static int make_raw_rw_request(void)
|
|||
fsector_t > buffer_max ||
|
||||
fsector_t < buffer_min ||
|
||||
((CT(COMMAND) == FD_READ ||
|
||||
(!in_sector_offset && current_req->nr_sectors >= ssize)) &&
|
||||
(!in_sector_offset && blk_rq_sectors(current_req) >= ssize)) &&
|
||||
max_sector > 2 * max_buffer_sectors + buffer_min &&
|
||||
max_size + fsector_t > 2 * max_buffer_sectors + buffer_min)
|
||||
/* not enough space */
|
||||
|
|
@ -2879,8 +2878,8 @@ static int make_raw_rw_request(void)
|
|||
printk("write\n");
|
||||
return 0;
|
||||
}
|
||||
} else if (raw_cmd->length > current_req->nr_sectors << 9 ||
|
||||
current_count_sectors > current_req->nr_sectors) {
|
||||
} else if (raw_cmd->length > blk_rq_bytes(current_req) ||
|
||||
current_count_sectors > blk_rq_sectors(current_req)) {
|
||||
DPRINT("buffer overrun in direct transfer\n");
|
||||
return 0;
|
||||
} else if (raw_cmd->length < current_count_sectors << 9) {
|
||||
|
|
@ -2913,7 +2912,7 @@ static void redo_fd_request(void)
|
|||
struct request *req;
|
||||
|
||||
spin_lock_irq(floppy_queue->queue_lock);
|
||||
req = elv_next_request(floppy_queue);
|
||||
req = blk_fetch_request(floppy_queue);
|
||||
spin_unlock_irq(floppy_queue->queue_lock);
|
||||
if (!req) {
|
||||
do_floppy = NULL;
|
||||
|
|
@ -2990,8 +2989,9 @@ static void do_fd_request(struct request_queue * q)
|
|||
if (usage_count == 0) {
|
||||
printk("warning: usage count=0, current_req=%p exiting\n",
|
||||
current_req);
|
||||
printk("sect=%ld type=%x flags=%x\n", (long)current_req->sector,
|
||||
current_req->cmd_type, current_req->cmd_flags);
|
||||
printk("sect=%ld type=%x flags=%x\n",
|
||||
(long)blk_rq_pos(current_req), current_req->cmd_type,
|
||||
current_req->cmd_flags);
|
||||
return;
|
||||
}
|
||||
if (test_bit(0, &fdc_busy)) {
|
||||
|
|
@ -4148,6 +4148,24 @@ static void floppy_device_release(struct device *dev)
|
|||
{
|
||||
}
|
||||
|
||||
static int floppy_resume(struct platform_device *dev)
|
||||
{
|
||||
int fdc;
|
||||
|
||||
for (fdc = 0; fdc < N_FDC; fdc++)
|
||||
if (FDCS->address != -1)
|
||||
user_reset_fdc(-1, FD_RESET_ALWAYS, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver floppy_driver = {
|
||||
.resume = floppy_resume,
|
||||
.driver = {
|
||||
.name = "floppy",
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device floppy_device[N_DRIVE];
|
||||
|
||||
static struct kobject *floppy_find(dev_t dev, int *part, void *data)
|
||||
|
|
@ -4196,10 +4214,14 @@ static int __init floppy_init(void)
|
|||
if (err)
|
||||
goto out_put_disk;
|
||||
|
||||
err = platform_driver_register(&floppy_driver);
|
||||
if (err)
|
||||
goto out_unreg_blkdev;
|
||||
|
||||
floppy_queue = blk_init_queue(do_fd_request, &floppy_lock);
|
||||
if (!floppy_queue) {
|
||||
err = -ENOMEM;
|
||||
goto out_unreg_blkdev;
|
||||
goto out_unreg_driver;
|
||||
}
|
||||
blk_queue_max_sectors(floppy_queue, 64);
|
||||
|
||||
|
|
@ -4346,6 +4368,8 @@ out_flush_work:
|
|||
out_unreg_region:
|
||||
blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
|
||||
blk_cleanup_queue(floppy_queue);
|
||||
out_unreg_driver:
|
||||
platform_driver_unregister(&floppy_driver);
|
||||
out_unreg_blkdev:
|
||||
unregister_blkdev(FLOPPY_MAJOR, "fd");
|
||||
out_put_disk:
|
||||
|
|
@ -4566,6 +4590,7 @@ static void __exit floppy_module_exit(void)
|
|||
|
||||
blk_unregister_region(MKDEV(FLOPPY_MAJOR, 0), 256);
|
||||
unregister_blkdev(FLOPPY_MAJOR, "fd");
|
||||
platform_driver_unregister(&floppy_driver);
|
||||
|
||||
for (drive = 0; drive < N_DRIVE; drive++) {
|
||||
del_timer_sync(&motor_off_timer[drive]);
|
||||
|
|
|
|||
|
|
@ -98,10 +98,9 @@
|
|||
|
||||
static DEFINE_SPINLOCK(hd_lock);
|
||||
static struct request_queue *hd_queue;
|
||||
static struct request *hd_req;
|
||||
|
||||
#define MAJOR_NR HD_MAJOR
|
||||
#define QUEUE (hd_queue)
|
||||
#define CURRENT elv_next_request(hd_queue)
|
||||
|
||||
#define TIMEOUT_VALUE (6*HZ)
|
||||
#define HD_DELAY 0
|
||||
|
|
@ -195,11 +194,24 @@ static void __init hd_setup(char *str, int *ints)
|
|||
NR_HD = hdind+1;
|
||||
}
|
||||
|
||||
static bool hd_end_request(int err, unsigned int bytes)
|
||||
{
|
||||
if (__blk_end_request(hd_req, err, bytes))
|
||||
return true;
|
||||
hd_req = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hd_end_request_cur(int err)
|
||||
{
|
||||
return hd_end_request(err, blk_rq_cur_bytes(hd_req));
|
||||
}
|
||||
|
||||
static void dump_status(const char *msg, unsigned int stat)
|
||||
{
|
||||
char *name = "hd?";
|
||||
if (CURRENT)
|
||||
name = CURRENT->rq_disk->disk_name;
|
||||
if (hd_req)
|
||||
name = hd_req->rq_disk->disk_name;
|
||||
|
||||
#ifdef VERBOSE_ERRORS
|
||||
printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
|
||||
|
|
@ -227,8 +239,8 @@ static void dump_status(const char *msg, unsigned int stat)
|
|||
if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) {
|
||||
printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL),
|
||||
inb(HD_CURRENT) & 0xf, inb(HD_SECTOR));
|
||||
if (CURRENT)
|
||||
printk(", sector=%ld", CURRENT->sector);
|
||||
if (hd_req)
|
||||
printk(", sector=%ld", blk_rq_pos(hd_req));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
|
@ -406,11 +418,12 @@ static void unexpected_hd_interrupt(void)
|
|||
*/
|
||||
static void bad_rw_intr(void)
|
||||
{
|
||||
struct request *req = CURRENT;
|
||||
struct request *req = hd_req;
|
||||
|
||||
if (req != NULL) {
|
||||
struct hd_i_struct *disk = req->rq_disk->private_data;
|
||||
if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
|
||||
end_request(req, 0);
|
||||
hd_end_request_cur(-EIO);
|
||||
disk->special_op = disk->recalibrate = 1;
|
||||
} else if (req->errors % RESET_FREQ == 0)
|
||||
reset = 1;
|
||||
|
|
@ -452,37 +465,30 @@ static void read_intr(void)
|
|||
bad_rw_intr();
|
||||
hd_request();
|
||||
return;
|
||||
|
||||
ok_to_read:
|
||||
req = CURRENT;
|
||||
req = hd_req;
|
||||
insw(HD_DATA, req->buffer, 256);
|
||||
req->sector++;
|
||||
req->buffer += 512;
|
||||
req->errors = 0;
|
||||
i = --req->nr_sectors;
|
||||
--req->current_nr_sectors;
|
||||
#ifdef DEBUG
|
||||
printk("%s: read: sector %ld, remaining = %ld, buffer=%p\n",
|
||||
req->rq_disk->disk_name, req->sector, req->nr_sectors,
|
||||
req->buffer+512);
|
||||
printk("%s: read: sector %ld, remaining = %u, buffer=%p\n",
|
||||
req->rq_disk->disk_name, blk_rq_pos(req) + 1,
|
||||
blk_rq_sectors(req) - 1, req->buffer+512);
|
||||
#endif
|
||||
if (req->current_nr_sectors <= 0)
|
||||
end_request(req, 1);
|
||||
if (i > 0) {
|
||||
if (hd_end_request(0, 512)) {
|
||||
SET_HANDLER(&read_intr);
|
||||
return;
|
||||
}
|
||||
|
||||
(void) inb_p(HD_STATUS);
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
if (elv_next_request(QUEUE))
|
||||
hd_request();
|
||||
return;
|
||||
hd_request();
|
||||
}
|
||||
|
||||
static void write_intr(void)
|
||||
{
|
||||
struct request *req = CURRENT;
|
||||
struct request *req = hd_req;
|
||||
int i;
|
||||
int retries = 100000;
|
||||
|
||||
|
|
@ -492,30 +498,25 @@ static void write_intr(void)
|
|||
continue;
|
||||
if (!OK_STATUS(i))
|
||||
break;
|
||||
if ((req->nr_sectors <= 1) || (i & DRQ_STAT))
|
||||
if ((blk_rq_sectors(req) <= 1) || (i & DRQ_STAT))
|
||||
goto ok_to_write;
|
||||
} while (--retries > 0);
|
||||
dump_status("write_intr", i);
|
||||
bad_rw_intr();
|
||||
hd_request();
|
||||
return;
|
||||
|
||||
ok_to_write:
|
||||
req->sector++;
|
||||
i = --req->nr_sectors;
|
||||
--req->current_nr_sectors;
|
||||
req->buffer += 512;
|
||||
if (!i || (req->bio && req->current_nr_sectors <= 0))
|
||||
end_request(req, 1);
|
||||
if (i > 0) {
|
||||
if (hd_end_request(0, 512)) {
|
||||
SET_HANDLER(&write_intr);
|
||||
outsw(HD_DATA, req->buffer, 256);
|
||||
} else {
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
hd_request();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
#if (HD_DELAY > 0)
|
||||
last_req = read_timer();
|
||||
#endif
|
||||
hd_request();
|
||||
}
|
||||
|
||||
static void recal_intr(void)
|
||||
|
|
@ -537,18 +538,18 @@ static void hd_times_out(unsigned long dummy)
|
|||
|
||||
do_hd = NULL;
|
||||
|
||||
if (!CURRENT)
|
||||
if (!hd_req)
|
||||
return;
|
||||
|
||||
spin_lock_irq(hd_queue->queue_lock);
|
||||
reset = 1;
|
||||
name = CURRENT->rq_disk->disk_name;
|
||||
name = hd_req->rq_disk->disk_name;
|
||||
printk("%s: timeout\n", name);
|
||||
if (++CURRENT->errors >= MAX_ERRORS) {
|
||||
if (++hd_req->errors >= MAX_ERRORS) {
|
||||
#ifdef DEBUG
|
||||
printk("%s: too many errors\n", name);
|
||||
#endif
|
||||
end_request(CURRENT, 0);
|
||||
hd_end_request_cur(-EIO);
|
||||
}
|
||||
hd_request();
|
||||
spin_unlock_irq(hd_queue->queue_lock);
|
||||
|
|
@ -563,7 +564,7 @@ static int do_special_op(struct hd_i_struct *disk, struct request *req)
|
|||
}
|
||||
if (disk->head > 16) {
|
||||
printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name);
|
||||
end_request(req, 0);
|
||||
hd_end_request_cur(-EIO);
|
||||
}
|
||||
disk->special_op = 0;
|
||||
return 1;
|
||||
|
|
@ -590,24 +591,27 @@ static void hd_request(void)
|
|||
repeat:
|
||||
del_timer(&device_timer);
|
||||
|
||||
req = CURRENT;
|
||||
if (!req) {
|
||||
do_hd = NULL;
|
||||
return;
|
||||
if (!hd_req) {
|
||||
hd_req = blk_fetch_request(hd_queue);
|
||||
if (!hd_req) {
|
||||
do_hd = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
req = hd_req;
|
||||
|
||||
if (reset) {
|
||||
reset_hd();
|
||||
return;
|
||||
}
|
||||
disk = req->rq_disk->private_data;
|
||||
block = req->sector;
|
||||
nsect = req->nr_sectors;
|
||||
block = blk_rq_pos(req);
|
||||
nsect = blk_rq_sectors(req);
|
||||
if (block >= get_capacity(req->rq_disk) ||
|
||||
((block+nsect) > get_capacity(req->rq_disk))) {
|
||||
printk("%s: bad access: block=%d, count=%d\n",
|
||||
req->rq_disk->disk_name, block, nsect);
|
||||
end_request(req, 0);
|
||||
hd_end_request_cur(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
|
@ -647,7 +651,7 @@ repeat:
|
|||
break;
|
||||
default:
|
||||
printk("unknown hd-command\n");
|
||||
end_request(req, 0);
|
||||
hd_end_request_cur(-EIO);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -720,7 +724,7 @@ static int __init hd_init(void)
|
|||
blk_queue_max_sectors(hd_queue, 255);
|
||||
init_timer(&device_timer);
|
||||
device_timer.function = hd_times_out;
|
||||
blk_queue_hardsect_size(hd_queue, 512);
|
||||
blk_queue_logical_block_size(hd_queue, 512);
|
||||
|
||||
if (!NR_HD) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -511,11 +511,7 @@ out:
|
|||
*/
|
||||
static void loop_add_bio(struct loop_device *lo, struct bio *bio)
|
||||
{
|
||||
if (lo->lo_biotail) {
|
||||
lo->lo_biotail->bi_next = bio;
|
||||
lo->lo_biotail = bio;
|
||||
} else
|
||||
lo->lo_bio = lo->lo_biotail = bio;
|
||||
bio_list_add(&lo->lo_bio_list, bio);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -523,16 +519,7 @@ static void loop_add_bio(struct loop_device *lo, struct bio *bio)
|
|||
*/
|
||||
static struct bio *loop_get_bio(struct loop_device *lo)
|
||||
{
|
||||
struct bio *bio;
|
||||
|
||||
if ((bio = lo->lo_bio)) {
|
||||
if (bio == lo->lo_biotail)
|
||||
lo->lo_biotail = NULL;
|
||||
lo->lo_bio = bio->bi_next;
|
||||
bio->bi_next = NULL;
|
||||
}
|
||||
|
||||
return bio;
|
||||
return bio_list_pop(&lo->lo_bio_list);
|
||||
}
|
||||
|
||||
static int loop_make_request(struct request_queue *q, struct bio *old_bio)
|
||||
|
|
@ -609,12 +596,13 @@ static int loop_thread(void *data)
|
|||
|
||||
set_user_nice(current, -20);
|
||||
|
||||
while (!kthread_should_stop() || lo->lo_bio) {
|
||||
while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) {
|
||||
|
||||
wait_event_interruptible(lo->lo_event,
|
||||
lo->lo_bio || kthread_should_stop());
|
||||
!bio_list_empty(&lo->lo_bio_list) ||
|
||||
kthread_should_stop());
|
||||
|
||||
if (!lo->lo_bio)
|
||||
if (bio_list_empty(&lo->lo_bio_list))
|
||||
continue;
|
||||
spin_lock_irq(&lo->lo_lock);
|
||||
bio = loop_get_bio(lo);
|
||||
|
|
@ -721,10 +709,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
|
|||
if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
|
||||
goto out_putf;
|
||||
|
||||
/* new backing store needs to support loop (eg splice_read) */
|
||||
if (!inode->i_fop->splice_read)
|
||||
goto out_putf;
|
||||
|
||||
/* size of the new backing store needs to be the same */
|
||||
if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
|
||||
goto out_putf;
|
||||
|
|
@ -800,12 +784,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
|
|||
error = -EINVAL;
|
||||
if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
|
||||
const struct address_space_operations *aops = mapping->a_ops;
|
||||
/*
|
||||
* If we can't read - sorry. If we only can't write - well,
|
||||
* it's going to be read-only.
|
||||
*/
|
||||
if (!file->f_op->splice_read)
|
||||
goto out_putf;
|
||||
|
||||
if (aops->write_begin)
|
||||
lo_flags |= LO_FLAGS_USE_AOPS;
|
||||
if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
|
||||
|
|
@ -841,7 +820,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
|
|||
lo->old_gfp_mask = mapping_gfp_mask(mapping);
|
||||
mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
|
||||
|
||||
lo->lo_bio = lo->lo_biotail = NULL;
|
||||
bio_list_init(&lo->lo_bio_list);
|
||||
|
||||
/*
|
||||
* set queue make_request_fn, and add limits based on lower level
|
||||
|
|
|
|||
|
|
@ -17,71 +17,220 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/hdreg.h>
|
||||
#include <linux/libata.h>
|
||||
#include <linux/ata.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/mg_disk.h>
|
||||
|
||||
#define MG_RES_SEC (CONFIG_MG_DISK_RES << 1)
|
||||
|
||||
/* name for block device */
|
||||
#define MG_DISK_NAME "mgd"
|
||||
/* name for platform device */
|
||||
#define MG_DEV_NAME "mg_disk"
|
||||
|
||||
#define MG_DISK_MAJ 0
|
||||
#define MG_DISK_MAX_PART 16
|
||||
#define MG_SECTOR_SIZE 512
|
||||
#define MG_MAX_SECTS 256
|
||||
|
||||
/* Register offsets */
|
||||
#define MG_BUFF_OFFSET 0x8000
|
||||
#define MG_STORAGE_BUFFER_SIZE 0x200
|
||||
#define MG_REG_OFFSET 0xC000
|
||||
#define MG_REG_FEATURE (MG_REG_OFFSET + 2) /* write case */
|
||||
#define MG_REG_ERROR (MG_REG_OFFSET + 2) /* read case */
|
||||
#define MG_REG_SECT_CNT (MG_REG_OFFSET + 4)
|
||||
#define MG_REG_SECT_NUM (MG_REG_OFFSET + 6)
|
||||
#define MG_REG_CYL_LOW (MG_REG_OFFSET + 8)
|
||||
#define MG_REG_CYL_HIGH (MG_REG_OFFSET + 0xA)
|
||||
#define MG_REG_DRV_HEAD (MG_REG_OFFSET + 0xC)
|
||||
#define MG_REG_COMMAND (MG_REG_OFFSET + 0xE) /* write case */
|
||||
#define MG_REG_STATUS (MG_REG_OFFSET + 0xE) /* read case */
|
||||
#define MG_REG_DRV_CTRL (MG_REG_OFFSET + 0x10)
|
||||
#define MG_REG_BURST_CTRL (MG_REG_OFFSET + 0x12)
|
||||
|
||||
/* handy status */
|
||||
#define MG_STAT_READY (ATA_DRDY | ATA_DSC)
|
||||
#define MG_READY_OK(s) (((s) & (MG_STAT_READY | (ATA_BUSY | ATA_DF | \
|
||||
ATA_ERR))) == MG_STAT_READY)
|
||||
|
||||
/* error code for others */
|
||||
#define MG_ERR_NONE 0
|
||||
#define MG_ERR_TIMEOUT 0x100
|
||||
#define MG_ERR_INIT_STAT 0x101
|
||||
#define MG_ERR_TRANSLATION 0x102
|
||||
#define MG_ERR_CTRL_RST 0x103
|
||||
#define MG_ERR_INV_STAT 0x104
|
||||
#define MG_ERR_RSTOUT 0x105
|
||||
|
||||
#define MG_MAX_ERRORS 6 /* Max read/write errors */
|
||||
|
||||
/* command */
|
||||
#define MG_CMD_RD 0x20
|
||||
#define MG_CMD_WR 0x30
|
||||
#define MG_CMD_SLEEP 0x99
|
||||
#define MG_CMD_WAKEUP 0xC3
|
||||
#define MG_CMD_ID 0xEC
|
||||
#define MG_CMD_WR_CONF 0x3C
|
||||
#define MG_CMD_RD_CONF 0x40
|
||||
|
||||
/* operation mode */
|
||||
#define MG_OP_CASCADE (1 << 0)
|
||||
#define MG_OP_CASCADE_SYNC_RD (1 << 1)
|
||||
#define MG_OP_CASCADE_SYNC_WR (1 << 2)
|
||||
#define MG_OP_INTERLEAVE (1 << 3)
|
||||
|
||||
/* synchronous */
|
||||
#define MG_BURST_LAT_4 (3 << 4)
|
||||
#define MG_BURST_LAT_5 (4 << 4)
|
||||
#define MG_BURST_LAT_6 (5 << 4)
|
||||
#define MG_BURST_LAT_7 (6 << 4)
|
||||
#define MG_BURST_LAT_8 (7 << 4)
|
||||
#define MG_BURST_LEN_4 (1 << 1)
|
||||
#define MG_BURST_LEN_8 (2 << 1)
|
||||
#define MG_BURST_LEN_16 (3 << 1)
|
||||
#define MG_BURST_LEN_32 (4 << 1)
|
||||
#define MG_BURST_LEN_CONT (0 << 1)
|
||||
|
||||
/* timeout value (unit: ms) */
|
||||
#define MG_TMAX_CONF_TO_CMD 1
|
||||
#define MG_TMAX_WAIT_RD_DRQ 10
|
||||
#define MG_TMAX_WAIT_WR_DRQ 500
|
||||
#define MG_TMAX_RST_TO_BUSY 10
|
||||
#define MG_TMAX_HDRST_TO_RDY 500
|
||||
#define MG_TMAX_SWRST_TO_RDY 500
|
||||
#define MG_TMAX_RSTOUT 3000
|
||||
|
||||
/* device attribution */
|
||||
/* use mflash as boot device */
|
||||
#define MG_BOOT_DEV (1 << 0)
|
||||
/* use mflash as storage device */
|
||||
#define MG_STORAGE_DEV (1 << 1)
|
||||
/* same as MG_STORAGE_DEV, but bootloader already done reset sequence */
|
||||
#define MG_STORAGE_DEV_SKIP_RST (1 << 2)
|
||||
|
||||
#define MG_DEV_MASK (MG_BOOT_DEV | MG_STORAGE_DEV | MG_STORAGE_DEV_SKIP_RST)
|
||||
|
||||
/* names of GPIO resource */
|
||||
#define MG_RST_PIN "mg_rst"
|
||||
/* except MG_BOOT_DEV, reset-out pin should be assigned */
|
||||
#define MG_RSTOUT_PIN "mg_rstout"
|
||||
|
||||
/* private driver data */
|
||||
struct mg_drv_data {
|
||||
/* disk resource */
|
||||
u32 use_polling;
|
||||
|
||||
/* device attribution */
|
||||
u32 dev_attr;
|
||||
|
||||
/* internally used */
|
||||
struct mg_host *host;
|
||||
};
|
||||
|
||||
/* main structure for mflash driver */
|
||||
struct mg_host {
|
||||
struct device *dev;
|
||||
|
||||
struct request_queue *breq;
|
||||
struct request *req;
|
||||
spinlock_t lock;
|
||||
struct gendisk *gd;
|
||||
|
||||
struct timer_list timer;
|
||||
void (*mg_do_intr) (struct mg_host *);
|
||||
|
||||
u16 id[ATA_ID_WORDS];
|
||||
|
||||
u16 cyls;
|
||||
u16 heads;
|
||||
u16 sectors;
|
||||
u32 n_sectors;
|
||||
u32 nres_sectors;
|
||||
|
||||
void __iomem *dev_base;
|
||||
unsigned int irq;
|
||||
unsigned int rst;
|
||||
unsigned int rstout;
|
||||
|
||||
u32 major;
|
||||
u32 error;
|
||||
};
|
||||
|
||||
/*
|
||||
* Debugging macro and defines
|
||||
*/
|
||||
#undef DO_MG_DEBUG
|
||||
#ifdef DO_MG_DEBUG
|
||||
# define MG_DBG(fmt, args...) \
|
||||
printk(KERN_DEBUG "%s:%d "fmt, __func__, __LINE__, ##args)
|
||||
#else /* CONFIG_MG_DEBUG */
|
||||
# define MG_DBG(fmt, args...) do { } while (0)
|
||||
#endif /* CONFIG_MG_DEBUG */
|
||||
|
||||
static void mg_request(struct request_queue *);
|
||||
|
||||
static bool mg_end_request(struct mg_host *host, int err, unsigned int nr_bytes)
|
||||
{
|
||||
if (__blk_end_request(host->req, err, nr_bytes))
|
||||
return true;
|
||||
|
||||
host->req = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool mg_end_request_cur(struct mg_host *host, int err)
|
||||
{
|
||||
return mg_end_request(host, err, blk_rq_cur_bytes(host->req));
|
||||
}
|
||||
|
||||
static void mg_dump_status(const char *msg, unsigned int stat,
|
||||
struct mg_host *host)
|
||||
{
|
||||
char *name = MG_DISK_NAME;
|
||||
struct request *req;
|
||||
|
||||
if (host->breq) {
|
||||
req = elv_next_request(host->breq);
|
||||
if (req)
|
||||
name = req->rq_disk->disk_name;
|
||||
}
|
||||
if (host->req)
|
||||
name = host->req->rq_disk->disk_name;
|
||||
|
||||
printk(KERN_ERR "%s: %s: status=0x%02x { ", name, msg, stat & 0xff);
|
||||
if (stat & MG_REG_STATUS_BIT_BUSY)
|
||||
if (stat & ATA_BUSY)
|
||||
printk("Busy ");
|
||||
if (stat & MG_REG_STATUS_BIT_READY)
|
||||
if (stat & ATA_DRDY)
|
||||
printk("DriveReady ");
|
||||
if (stat & MG_REG_STATUS_BIT_WRITE_FAULT)
|
||||
if (stat & ATA_DF)
|
||||
printk("WriteFault ");
|
||||
if (stat & MG_REG_STATUS_BIT_SEEK_DONE)
|
||||
if (stat & ATA_DSC)
|
||||
printk("SeekComplete ");
|
||||
if (stat & MG_REG_STATUS_BIT_DATA_REQ)
|
||||
if (stat & ATA_DRQ)
|
||||
printk("DataRequest ");
|
||||
if (stat & MG_REG_STATUS_BIT_CORRECTED_ERROR)
|
||||
if (stat & ATA_CORR)
|
||||
printk("CorrectedError ");
|
||||
if (stat & MG_REG_STATUS_BIT_ERROR)
|
||||
if (stat & ATA_ERR)
|
||||
printk("Error ");
|
||||
printk("}\n");
|
||||
if ((stat & MG_REG_STATUS_BIT_ERROR) == 0) {
|
||||
if ((stat & ATA_ERR) == 0) {
|
||||
host->error = 0;
|
||||
} else {
|
||||
host->error = inb((unsigned long)host->dev_base + MG_REG_ERROR);
|
||||
printk(KERN_ERR "%s: %s: error=0x%02x { ", name, msg,
|
||||
host->error & 0xff);
|
||||
if (host->error & MG_REG_ERR_BBK)
|
||||
if (host->error & ATA_BBK)
|
||||
printk("BadSector ");
|
||||
if (host->error & MG_REG_ERR_UNC)
|
||||
if (host->error & ATA_UNC)
|
||||
printk("UncorrectableError ");
|
||||
if (host->error & MG_REG_ERR_IDNF)
|
||||
if (host->error & ATA_IDNF)
|
||||
printk("SectorIdNotFound ");
|
||||
if (host->error & MG_REG_ERR_ABRT)
|
||||
if (host->error & ATA_ABORTED)
|
||||
printk("DriveStatusError ");
|
||||
if (host->error & MG_REG_ERR_AMNF)
|
||||
if (host->error & ATA_AMNF)
|
||||
printk("AddrMarkNotFound ");
|
||||
printk("}");
|
||||
if (host->error &
|
||||
(MG_REG_ERR_BBK | MG_REG_ERR_UNC |
|
||||
MG_REG_ERR_IDNF | MG_REG_ERR_AMNF)) {
|
||||
if (host->breq) {
|
||||
req = elv_next_request(host->breq);
|
||||
if (req)
|
||||
printk(", sector=%u", (u32)req->sector);
|
||||
}
|
||||
|
||||
if (host->error & (ATA_BBK | ATA_UNC | ATA_IDNF | ATA_AMNF)) {
|
||||
if (host->req)
|
||||
printk(", sector=%u",
|
||||
(unsigned int)blk_rq_pos(host->req));
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
|
|
@ -100,12 +249,12 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
|
|||
|
||||
do {
|
||||
cur_jiffies = jiffies;
|
||||
if (status & MG_REG_STATUS_BIT_BUSY) {
|
||||
if (expect == MG_REG_STATUS_BIT_BUSY)
|
||||
if (status & ATA_BUSY) {
|
||||
if (expect == ATA_BUSY)
|
||||
break;
|
||||
} else {
|
||||
/* Check the error condition! */
|
||||
if (status & MG_REG_STATUS_BIT_ERROR) {
|
||||
if (status & ATA_ERR) {
|
||||
mg_dump_status("mg_wait", status, host);
|
||||
break;
|
||||
}
|
||||
|
|
@ -114,8 +263,8 @@ static unsigned int mg_wait(struct mg_host *host, u32 expect, u32 msec)
|
|||
if (MG_READY_OK(status))
|
||||
break;
|
||||
|
||||
if (expect == MG_REG_STATUS_BIT_DATA_REQ)
|
||||
if (status & MG_REG_STATUS_BIT_DATA_REQ)
|
||||
if (expect == ATA_DRQ)
|
||||
if (status & ATA_DRQ)
|
||||
break;
|
||||
}
|
||||
if (!msec) {
|
||||
|
|
@ -173,6 +322,42 @@ static irqreturn_t mg_irq(int irq, void *dev_id)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* local copy of ata_id_string() */
|
||||
static void mg_id_string(const u16 *id, unsigned char *s,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
BUG_ON(len & 1);
|
||||
|
||||
while (len > 0) {
|
||||
c = id[ofs] >> 8;
|
||||
*s = c;
|
||||
s++;
|
||||
|
||||
c = id[ofs] & 0xff;
|
||||
*s = c;
|
||||
s++;
|
||||
|
||||
ofs++;
|
||||
len -= 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* local copy of ata_id_c_string() */
|
||||
static void mg_id_c_string(const u16 *id, unsigned char *s,
|
||||
unsigned int ofs, unsigned int len)
|
||||
{
|
||||
unsigned char *p;
|
||||
|
||||
mg_id_string(id, s, ofs, len - 1);
|
||||
|
||||
p = s + strnlen(s, len - 1);
|
||||
while (p > s && p[-1] == ' ')
|
||||
p--;
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
static int mg_get_disk_id(struct mg_host *host)
|
||||
{
|
||||
u32 i;
|
||||
|
|
@ -184,12 +369,10 @@ static int mg_get_disk_id(struct mg_host *host)
|
|||
char serial[ATA_ID_SERNO_LEN + 1];
|
||||
|
||||
if (!prv_data->use_polling)
|
||||
outb(MG_REG_CTRL_INTR_DISABLE,
|
||||
(unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
|
||||
outb(MG_CMD_ID, (unsigned long)host->dev_base + MG_REG_COMMAND);
|
||||
err = mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_RD_DRQ);
|
||||
err = mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_RD_DRQ);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -219,9 +402,9 @@ static int mg_get_disk_id(struct mg_host *host)
|
|||
host->n_sectors -= host->nres_sectors;
|
||||
}
|
||||
|
||||
ata_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev));
|
||||
ata_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
|
||||
ata_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
|
||||
mg_id_c_string(id, fwrev, ATA_ID_FW_REV, sizeof(fwrev));
|
||||
mg_id_c_string(id, model, ATA_ID_PROD, sizeof(model));
|
||||
mg_id_c_string(id, serial, ATA_ID_SERNO, sizeof(serial));
|
||||
printk(KERN_INFO "mg_disk: model: %s\n", model);
|
||||
printk(KERN_INFO "mg_disk: firm: %.8s\n", fwrev);
|
||||
printk(KERN_INFO "mg_disk: serial: %s\n", serial);
|
||||
|
|
@ -229,8 +412,7 @@ static int mg_get_disk_id(struct mg_host *host)
|
|||
host->n_sectors, host->nres_sectors);
|
||||
|
||||
if (!prv_data->use_polling)
|
||||
outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
@ -244,7 +426,7 @@ static int mg_disk_init(struct mg_host *host)
|
|||
|
||||
/* hdd rst low */
|
||||
gpio_set_value(host->rst, 0);
|
||||
err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY);
|
||||
err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
|
@ -255,17 +437,14 @@ static int mg_disk_init(struct mg_host *host)
|
|||
return err;
|
||||
|
||||
/* soft reset on */
|
||||
outb(MG_REG_CTRL_RESET |
|
||||
(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE :
|
||||
MG_REG_CTRL_INTR_ENABLE),
|
||||
outb(ATA_SRST | (prv_data->use_polling ? ATA_NIEN : 0),
|
||||
(unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
err = mg_wait(host, MG_REG_STATUS_BIT_BUSY, MG_TMAX_RST_TO_BUSY);
|
||||
err = mg_wait(host, ATA_BUSY, MG_TMAX_RST_TO_BUSY);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* soft reset off */
|
||||
outb(prv_data->use_polling ? MG_REG_CTRL_INTR_DISABLE :
|
||||
MG_REG_CTRL_INTR_ENABLE,
|
||||
outb(prv_data->use_polling ? ATA_NIEN : 0,
|
||||
(unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
err = mg_wait(host, MG_STAT_READY, MG_TMAX_SWRST_TO_RDY);
|
||||
if (err)
|
||||
|
|
@ -281,11 +460,10 @@ static int mg_disk_init(struct mg_host *host)
|
|||
|
||||
static void mg_bad_rw_intr(struct mg_host *host)
|
||||
{
|
||||
struct request *req = elv_next_request(host->breq);
|
||||
if (req != NULL)
|
||||
if (++req->errors >= MG_MAX_ERRORS ||
|
||||
host->error == MG_ERR_TIMEOUT)
|
||||
end_request(req, 0);
|
||||
if (host->req)
|
||||
if (++host->req->errors >= MG_MAX_ERRORS ||
|
||||
host->error == MG_ERR_TIMEOUT)
|
||||
mg_end_request_cur(host, -EIO);
|
||||
}
|
||||
|
||||
static unsigned int mg_out(struct mg_host *host,
|
||||
|
|
@ -311,7 +489,7 @@ static unsigned int mg_out(struct mg_host *host,
|
|||
MG_REG_CYL_LOW);
|
||||
outb((u8)(sect_num >> 16), (unsigned long)host->dev_base +
|
||||
MG_REG_CYL_HIGH);
|
||||
outb((u8)((sect_num >> 24) | MG_REG_HEAD_LBA_MODE),
|
||||
outb((u8)((sect_num >> 24) | ATA_LBA | ATA_DEVICE_OBS),
|
||||
(unsigned long)host->dev_base + MG_REG_DRV_HEAD);
|
||||
outb(cmd, (unsigned long)host->dev_base + MG_REG_COMMAND);
|
||||
return MG_ERR_NONE;
|
||||
|
|
@ -319,105 +497,77 @@ static unsigned int mg_out(struct mg_host *host,
|
|||
|
||||
static void mg_read(struct request *req)
|
||||
{
|
||||
u32 remains, j;
|
||||
u32 j;
|
||||
struct mg_host *host = req->rq_disk->private_data;
|
||||
|
||||
remains = req->nr_sectors;
|
||||
|
||||
if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_RD, NULL) !=
|
||||
MG_ERR_NONE)
|
||||
if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req),
|
||||
MG_CMD_RD, NULL) != MG_ERR_NONE)
|
||||
mg_bad_rw_intr(host);
|
||||
|
||||
MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
|
||||
remains, req->sector, req->buffer);
|
||||
blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
|
||||
|
||||
while (remains) {
|
||||
if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ,
|
||||
MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) {
|
||||
do {
|
||||
u16 *buff = (u16 *)req->buffer;
|
||||
|
||||
if (mg_wait(host, ATA_DRQ,
|
||||
MG_TMAX_WAIT_RD_DRQ) != MG_ERR_NONE) {
|
||||
mg_bad_rw_intr(host);
|
||||
return;
|
||||
}
|
||||
for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
|
||||
*(u16 *)req->buffer =
|
||||
inw((unsigned long)host->dev_base +
|
||||
MG_BUFF_OFFSET + (j << 1));
|
||||
req->buffer += 2;
|
||||
}
|
||||
|
||||
req->sector++;
|
||||
req->errors = 0;
|
||||
remains = --req->nr_sectors;
|
||||
--req->current_nr_sectors;
|
||||
|
||||
if (req->current_nr_sectors <= 0) {
|
||||
MG_DBG("remain : %d sects\n", remains);
|
||||
end_request(req, 1);
|
||||
if (remains > 0)
|
||||
req = elv_next_request(host->breq);
|
||||
}
|
||||
for (j = 0; j < MG_SECTOR_SIZE >> 1; j++)
|
||||
*buff++ = inw((unsigned long)host->dev_base +
|
||||
MG_BUFF_OFFSET + (j << 1));
|
||||
|
||||
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base +
|
||||
MG_REG_COMMAND);
|
||||
}
|
||||
} while (mg_end_request(host, 0, MG_SECTOR_SIZE));
|
||||
}
|
||||
|
||||
static void mg_write(struct request *req)
|
||||
{
|
||||
u32 remains, j;
|
||||
u32 j;
|
||||
struct mg_host *host = req->rq_disk->private_data;
|
||||
|
||||
remains = req->nr_sectors;
|
||||
|
||||
if (mg_out(host, req->sector, req->nr_sectors, MG_CMD_WR, NULL) !=
|
||||
MG_ERR_NONE) {
|
||||
if (mg_out(host, blk_rq_pos(req), blk_rq_sectors(req),
|
||||
MG_CMD_WR, NULL) != MG_ERR_NONE) {
|
||||
mg_bad_rw_intr(host);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
MG_DBG("requested %d sects (from %ld), buffer=0x%p\n",
|
||||
remains, req->sector, req->buffer);
|
||||
while (remains) {
|
||||
if (mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ,
|
||||
MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
|
||||
blk_rq_sectors(req), blk_rq_pos(req), req->buffer);
|
||||
|
||||
do {
|
||||
u16 *buff = (u16 *)req->buffer;
|
||||
|
||||
if (mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ) != MG_ERR_NONE) {
|
||||
mg_bad_rw_intr(host);
|
||||
return;
|
||||
}
|
||||
for (j = 0; j < MG_SECTOR_SIZE >> 1; j++) {
|
||||
outw(*(u16 *)req->buffer,
|
||||
(unsigned long)host->dev_base +
|
||||
MG_BUFF_OFFSET + (j << 1));
|
||||
req->buffer += 2;
|
||||
}
|
||||
req->sector++;
|
||||
remains = --req->nr_sectors;
|
||||
--req->current_nr_sectors;
|
||||
|
||||
if (req->current_nr_sectors <= 0) {
|
||||
MG_DBG("remain : %d sects\n", remains);
|
||||
end_request(req, 1);
|
||||
if (remains > 0)
|
||||
req = elv_next_request(host->breq);
|
||||
}
|
||||
for (j = 0; j < MG_SECTOR_SIZE >> 1; j++)
|
||||
outw(*buff++, (unsigned long)host->dev_base +
|
||||
MG_BUFF_OFFSET + (j << 1));
|
||||
|
||||
outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
|
||||
MG_REG_COMMAND);
|
||||
}
|
||||
} while (mg_end_request(host, 0, MG_SECTOR_SIZE));
|
||||
}
|
||||
|
||||
static void mg_read_intr(struct mg_host *host)
|
||||
{
|
||||
struct request *req = host->req;
|
||||
u32 i;
|
||||
struct request *req;
|
||||
u16 *buff;
|
||||
|
||||
/* check status */
|
||||
do {
|
||||
i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
|
||||
if (i & MG_REG_STATUS_BIT_BUSY)
|
||||
if (i & ATA_BUSY)
|
||||
break;
|
||||
if (!MG_READY_OK(i))
|
||||
break;
|
||||
if (i & MG_REG_STATUS_BIT_DATA_REQ)
|
||||
if (i & ATA_DRQ)
|
||||
goto ok_to_read;
|
||||
} while (0);
|
||||
mg_dump_status("mg_read_intr", i, host);
|
||||
|
|
@ -427,60 +577,42 @@ static void mg_read_intr(struct mg_host *host)
|
|||
|
||||
ok_to_read:
|
||||
/* get current segment of request */
|
||||
req = elv_next_request(host->breq);
|
||||
buff = (u16 *)req->buffer;
|
||||
|
||||
/* read 1 sector */
|
||||
for (i = 0; i < MG_SECTOR_SIZE >> 1; i++) {
|
||||
*(u16 *)req->buffer =
|
||||
inw((unsigned long)host->dev_base + MG_BUFF_OFFSET +
|
||||
(i << 1));
|
||||
req->buffer += 2;
|
||||
}
|
||||
for (i = 0; i < MG_SECTOR_SIZE >> 1; i++)
|
||||
*buff++ = inw((unsigned long)host->dev_base + MG_BUFF_OFFSET +
|
||||
(i << 1));
|
||||
|
||||
/* manipulate request */
|
||||
MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
|
||||
req->sector, req->nr_sectors - 1, req->buffer);
|
||||
|
||||
req->sector++;
|
||||
req->errors = 0;
|
||||
i = --req->nr_sectors;
|
||||
--req->current_nr_sectors;
|
||||
|
||||
/* let know if current segment done */
|
||||
if (req->current_nr_sectors <= 0)
|
||||
end_request(req, 1);
|
||||
|
||||
/* set handler if read remains */
|
||||
if (i > 0) {
|
||||
host->mg_do_intr = mg_read_intr;
|
||||
mod_timer(&host->timer, jiffies + 3 * HZ);
|
||||
}
|
||||
blk_rq_pos(req), blk_rq_sectors(req) - 1, req->buffer);
|
||||
|
||||
/* send read confirm */
|
||||
outb(MG_CMD_RD_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
|
||||
|
||||
/* goto next request */
|
||||
if (!i)
|
||||
if (mg_end_request(host, 0, MG_SECTOR_SIZE)) {
|
||||
/* set handler if read remains */
|
||||
host->mg_do_intr = mg_read_intr;
|
||||
mod_timer(&host->timer, jiffies + 3 * HZ);
|
||||
} else /* goto next request */
|
||||
mg_request(host->breq);
|
||||
}
|
||||
|
||||
static void mg_write_intr(struct mg_host *host)
|
||||
{
|
||||
struct request *req = host->req;
|
||||
u32 i, j;
|
||||
u16 *buff;
|
||||
struct request *req;
|
||||
|
||||
/* get current segment of request */
|
||||
req = elv_next_request(host->breq);
|
||||
bool rem;
|
||||
|
||||
/* check status */
|
||||
do {
|
||||
i = inb((unsigned long)host->dev_base + MG_REG_STATUS);
|
||||
if (i & MG_REG_STATUS_BIT_BUSY)
|
||||
if (i & ATA_BUSY)
|
||||
break;
|
||||
if (!MG_READY_OK(i))
|
||||
break;
|
||||
if ((req->nr_sectors <= 1) || (i & MG_REG_STATUS_BIT_DATA_REQ))
|
||||
if ((blk_rq_sectors(req) <= 1) || (i & ATA_DRQ))
|
||||
goto ok_to_write;
|
||||
} while (0);
|
||||
mg_dump_status("mg_write_intr", i, host);
|
||||
|
|
@ -489,18 +621,8 @@ static void mg_write_intr(struct mg_host *host)
|
|||
return;
|
||||
|
||||
ok_to_write:
|
||||
/* manipulate request */
|
||||
req->sector++;
|
||||
i = --req->nr_sectors;
|
||||
--req->current_nr_sectors;
|
||||
req->buffer += MG_SECTOR_SIZE;
|
||||
|
||||
/* let know if current segment or all done */
|
||||
if (!i || (req->bio && req->current_nr_sectors <= 0))
|
||||
end_request(req, 1);
|
||||
|
||||
/* write 1 sector and set handler if remains */
|
||||
if (i > 0) {
|
||||
if ((rem = mg_end_request(host, 0, MG_SECTOR_SIZE))) {
|
||||
/* write 1 sector and set handler if remains */
|
||||
buff = (u16 *)req->buffer;
|
||||
for (j = 0; j < MG_STORAGE_BUFFER_SIZE >> 1; j++) {
|
||||
outw(*buff, (unsigned long)host->dev_base +
|
||||
|
|
@ -508,7 +630,7 @@ ok_to_write:
|
|||
buff++;
|
||||
}
|
||||
MG_DBG("sector %ld, remaining=%ld, buffer=0x%p\n",
|
||||
req->sector, req->nr_sectors, req->buffer);
|
||||
blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
|
||||
host->mg_do_intr = mg_write_intr;
|
||||
mod_timer(&host->timer, jiffies + 3 * HZ);
|
||||
}
|
||||
|
|
@ -516,7 +638,7 @@ ok_to_write:
|
|||
/* send write confirm */
|
||||
outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base + MG_REG_COMMAND);
|
||||
|
||||
if (!i)
|
||||
if (!rem)
|
||||
mg_request(host->breq);
|
||||
}
|
||||
|
||||
|
|
@ -524,49 +646,45 @@ void mg_times_out(unsigned long data)
|
|||
{
|
||||
struct mg_host *host = (struct mg_host *)data;
|
||||
char *name;
|
||||
struct request *req;
|
||||
|
||||
spin_lock_irq(&host->lock);
|
||||
|
||||
req = elv_next_request(host->breq);
|
||||
if (!req)
|
||||
if (!host->req)
|
||||
goto out_unlock;
|
||||
|
||||
host->mg_do_intr = NULL;
|
||||
|
||||
name = req->rq_disk->disk_name;
|
||||
name = host->req->rq_disk->disk_name;
|
||||
printk(KERN_DEBUG "%s: timeout\n", name);
|
||||
|
||||
host->error = MG_ERR_TIMEOUT;
|
||||
mg_bad_rw_intr(host);
|
||||
|
||||
mg_request(host->breq);
|
||||
out_unlock:
|
||||
mg_request(host->breq);
|
||||
spin_unlock_irq(&host->lock);
|
||||
}
|
||||
|
||||
static void mg_request_poll(struct request_queue *q)
|
||||
{
|
||||
struct request *req;
|
||||
struct mg_host *host;
|
||||
struct mg_host *host = q->queuedata;
|
||||
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
host = req->rq_disk->private_data;
|
||||
if (blk_fs_request(req)) {
|
||||
switch (rq_data_dir(req)) {
|
||||
case READ:
|
||||
mg_read(req);
|
||||
while (1) {
|
||||
if (!host->req) {
|
||||
host->req = blk_fetch_request(q);
|
||||
if (!host->req)
|
||||
break;
|
||||
case WRITE:
|
||||
mg_write(req);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "%s:%d unknown command\n",
|
||||
__func__, __LINE__);
|
||||
end_request(req, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (unlikely(!blk_fs_request(host->req))) {
|
||||
mg_end_request_cur(host, -EIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rq_data_dir(host->req) == READ)
|
||||
mg_read(host->req);
|
||||
else
|
||||
mg_write(host->req);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -588,18 +706,15 @@ static unsigned int mg_issue_req(struct request *req,
|
|||
break;
|
||||
case WRITE:
|
||||
/* TODO : handler */
|
||||
outb(MG_REG_CTRL_INTR_DISABLE,
|
||||
(unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
if (mg_out(host, sect_num, sect_cnt, MG_CMD_WR, &mg_write_intr)
|
||||
!= MG_ERR_NONE) {
|
||||
mg_bad_rw_intr(host);
|
||||
return host->error;
|
||||
}
|
||||
del_timer(&host->timer);
|
||||
mg_wait(host, MG_REG_STATUS_BIT_DATA_REQ, MG_TMAX_WAIT_WR_DRQ);
|
||||
outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
mg_wait(host, ATA_DRQ, MG_TMAX_WAIT_WR_DRQ);
|
||||
outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
if (host->error) {
|
||||
mg_bad_rw_intr(host);
|
||||
return host->error;
|
||||
|
|
@ -614,11 +729,6 @@ static unsigned int mg_issue_req(struct request *req,
|
|||
outb(MG_CMD_WR_CONF, (unsigned long)host->dev_base +
|
||||
MG_REG_COMMAND);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "%s:%d unknown command\n",
|
||||
__func__, __LINE__);
|
||||
end_request(req, 0);
|
||||
break;
|
||||
}
|
||||
return MG_ERR_NONE;
|
||||
}
|
||||
|
|
@ -626,16 +736,17 @@ static unsigned int mg_issue_req(struct request *req,
|
|||
/* This function also called from IRQ context */
|
||||
static void mg_request(struct request_queue *q)
|
||||
{
|
||||
struct mg_host *host = q->queuedata;
|
||||
struct request *req;
|
||||
struct mg_host *host;
|
||||
u32 sect_num, sect_cnt;
|
||||
|
||||
while (1) {
|
||||
req = elv_next_request(q);
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
host = req->rq_disk->private_data;
|
||||
if (!host->req) {
|
||||
host->req = blk_fetch_request(q);
|
||||
if (!host->req)
|
||||
break;
|
||||
}
|
||||
req = host->req;
|
||||
|
||||
/* check unwanted request call */
|
||||
if (host->mg_do_intr)
|
||||
|
|
@ -643,9 +754,9 @@ static void mg_request(struct request_queue *q)
|
|||
|
||||
del_timer(&host->timer);
|
||||
|
||||
sect_num = req->sector;
|
||||
sect_num = blk_rq_pos(req);
|
||||
/* deal whole segments */
|
||||
sect_cnt = req->nr_sectors;
|
||||
sect_cnt = blk_rq_sectors(req);
|
||||
|
||||
/* sanity check */
|
||||
if (sect_num >= get_capacity(req->rq_disk) ||
|
||||
|
|
@ -655,12 +766,14 @@ static void mg_request(struct request_queue *q)
|
|||
"%s: bad access: sector=%d, count=%d\n",
|
||||
req->rq_disk->disk_name,
|
||||
sect_num, sect_cnt);
|
||||
end_request(req, 0);
|
||||
mg_end_request_cur(host, -EIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!blk_fs_request(req))
|
||||
return;
|
||||
if (unlikely(!blk_fs_request(req))) {
|
||||
mg_end_request_cur(host, -EIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!mg_issue_req(req, host, sect_num, sect_cnt))
|
||||
return;
|
||||
|
|
@ -690,9 +803,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
|
|||
return -EIO;
|
||||
|
||||
if (!prv_data->use_polling)
|
||||
outb(MG_REG_CTRL_INTR_DISABLE,
|
||||
(unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
outb(ATA_NIEN, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
|
||||
outb(MG_CMD_SLEEP, (unsigned long)host->dev_base + MG_REG_COMMAND);
|
||||
/* wait until mflash deep sleep */
|
||||
|
|
@ -700,9 +811,7 @@ static int mg_suspend(struct platform_device *plat_dev, pm_message_t state)
|
|||
|
||||
if (mg_wait(host, MG_STAT_READY, MG_TMAX_CONF_TO_CMD)) {
|
||||
if (!prv_data->use_polling)
|
||||
outb(MG_REG_CTRL_INTR_ENABLE,
|
||||
(unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
|
@ -725,8 +834,7 @@ static int mg_resume(struct platform_device *plat_dev)
|
|||
return -EIO;
|
||||
|
||||
if (!prv_data->use_polling)
|
||||
outb(MG_REG_CTRL_INTR_ENABLE, (unsigned long)host->dev_base +
|
||||
MG_REG_DRV_CTRL);
|
||||
outb(0, (unsigned long)host->dev_base + MG_REG_DRV_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -877,6 +985,7 @@ static int mg_probe(struct platform_device *plat_dev)
|
|||
__func__, __LINE__);
|
||||
goto probe_err_5;
|
||||
}
|
||||
host->breq->queuedata = host;
|
||||
|
||||
/* mflash is random device, thanx for the noop */
|
||||
elevator_exit(host->breq->elevator);
|
||||
|
|
@ -887,7 +996,7 @@ static int mg_probe(struct platform_device *plat_dev)
|
|||
goto probe_err_6;
|
||||
}
|
||||
blk_queue_max_sectors(host->breq, MG_MAX_SECTS);
|
||||
blk_queue_hardsect_size(host->breq, MG_SECTOR_SIZE);
|
||||
blk_queue_logical_block_size(host->breq, MG_SECTOR_SIZE);
|
||||
|
||||
init_timer(&host->timer);
|
||||
host->timer.function = mg_times_out;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ static void nbd_end_request(struct request *req)
|
|||
req, error ? "failed" : "done");
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
__blk_end_request(req, error, req->nr_sectors << 9);
|
||||
__blk_end_request_all(req, error);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -231,19 +231,19 @@ static int nbd_send_req(struct nbd_device *lo, struct request *req)
|
|||
{
|
||||
int result, flags;
|
||||
struct nbd_request request;
|
||||
unsigned long size = req->nr_sectors << 9;
|
||||
unsigned long size = blk_rq_bytes(req);
|
||||
|
||||
request.magic = htonl(NBD_REQUEST_MAGIC);
|
||||
request.type = htonl(nbd_cmd(req));
|
||||
request.from = cpu_to_be64((u64) req->sector << 9);
|
||||
request.from = cpu_to_be64((u64)blk_rq_pos(req) << 9);
|
||||
request.len = htonl(size);
|
||||
memcpy(request.handle, &req, sizeof(req));
|
||||
|
||||
dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%luB)\n",
|
||||
dprintk(DBG_TX, "%s: request %p: sending control (%s@%llu,%uB)\n",
|
||||
lo->disk->disk_name, req,
|
||||
nbdcmd_to_ascii(nbd_cmd(req)),
|
||||
(unsigned long long)req->sector << 9,
|
||||
req->nr_sectors << 9);
|
||||
(unsigned long long)blk_rq_pos(req) << 9,
|
||||
blk_rq_bytes(req));
|
||||
result = sock_xmit(lo, 1, &request, sizeof(request),
|
||||
(nbd_cmd(req) == NBD_CMD_WRITE) ? MSG_MORE : 0);
|
||||
if (result <= 0) {
|
||||
|
|
@ -533,11 +533,9 @@ static void do_nbd_request(struct request_queue *q)
|
|||
{
|
||||
struct request *req;
|
||||
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
while ((req = blk_fetch_request(q)) != NULL) {
|
||||
struct nbd_device *lo;
|
||||
|
||||
blkdev_dequeue_request(req);
|
||||
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%x)\n",
|
||||
|
|
@ -580,13 +578,6 @@ static int __nbd_ioctl(struct block_device *bdev, struct nbd_device *lo,
|
|||
blk_rq_init(NULL, &sreq);
|
||||
sreq.cmd_type = REQ_TYPE_SPECIAL;
|
||||
nbd_cmd(&sreq) = NBD_CMD_DISC;
|
||||
/*
|
||||
* Set these to sane values in case server implementation
|
||||
* fails to check the request type first and also to keep
|
||||
* debugging output cleaner.
|
||||
*/
|
||||
sreq.sector = 0;
|
||||
sreq.nr_sectors = 0;
|
||||
if (!lo->sock)
|
||||
return -EINVAL;
|
||||
nbd_send_req(lo, &sreq);
|
||||
|
|
|
|||
|
|
@ -719,32 +719,37 @@ static void do_pcd_request(struct request_queue * q)
|
|||
if (pcd_busy)
|
||||
return;
|
||||
while (1) {
|
||||
pcd_req = elv_next_request(q);
|
||||
if (!pcd_req)
|
||||
return;
|
||||
if (!pcd_req) {
|
||||
pcd_req = blk_fetch_request(q);
|
||||
if (!pcd_req)
|
||||
return;
|
||||
}
|
||||
|
||||
if (rq_data_dir(pcd_req) == READ) {
|
||||
struct pcd_unit *cd = pcd_req->rq_disk->private_data;
|
||||
if (cd != pcd_current)
|
||||
pcd_bufblk = -1;
|
||||
pcd_current = cd;
|
||||
pcd_sector = pcd_req->sector;
|
||||
pcd_count = pcd_req->current_nr_sectors;
|
||||
pcd_sector = blk_rq_pos(pcd_req);
|
||||
pcd_count = blk_rq_cur_sectors(pcd_req);
|
||||
pcd_buf = pcd_req->buffer;
|
||||
pcd_busy = 1;
|
||||
ps_set_intr(do_pcd_read, NULL, 0, nice);
|
||||
return;
|
||||
} else
|
||||
end_request(pcd_req, 0);
|
||||
} else {
|
||||
__blk_end_request_all(pcd_req, -EIO);
|
||||
pcd_req = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void next_request(int success)
|
||||
static inline void next_request(int err)
|
||||
{
|
||||
unsigned long saved_flags;
|
||||
|
||||
spin_lock_irqsave(&pcd_lock, saved_flags);
|
||||
end_request(pcd_req, success);
|
||||
if (!__blk_end_request_cur(pcd_req, err))
|
||||
pcd_req = NULL;
|
||||
pcd_busy = 0;
|
||||
do_pcd_request(pcd_queue);
|
||||
spin_unlock_irqrestore(&pcd_lock, saved_flags);
|
||||
|
|
@ -781,7 +786,7 @@ static void pcd_start(void)
|
|||
|
||||
if (pcd_command(pcd_current, rd_cmd, 2048, "read block")) {
|
||||
pcd_bufblk = -1;
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -796,7 +801,7 @@ static void do_pcd_read(void)
|
|||
pcd_retries = 0;
|
||||
pcd_transfer();
|
||||
if (!pcd_count) {
|
||||
next_request(1);
|
||||
next_request(0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -815,7 +820,7 @@ static void do_pcd_read_drq(void)
|
|||
return;
|
||||
}
|
||||
pcd_bufblk = -1;
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -410,10 +410,12 @@ static void run_fsm(void)
|
|||
pd_claimed = 0;
|
||||
phase = NULL;
|
||||
spin_lock_irqsave(&pd_lock, saved_flags);
|
||||
end_request(pd_req, res);
|
||||
pd_req = elv_next_request(pd_queue);
|
||||
if (!pd_req)
|
||||
stop = 1;
|
||||
if (!__blk_end_request_cur(pd_req,
|
||||
res == Ok ? 0 : -EIO)) {
|
||||
pd_req = blk_fetch_request(pd_queue);
|
||||
if (!pd_req)
|
||||
stop = 1;
|
||||
}
|
||||
spin_unlock_irqrestore(&pd_lock, saved_flags);
|
||||
if (stop)
|
||||
return;
|
||||
|
|
@ -443,11 +445,11 @@ static enum action do_pd_io_start(void)
|
|||
|
||||
pd_cmd = rq_data_dir(pd_req);
|
||||
if (pd_cmd == READ || pd_cmd == WRITE) {
|
||||
pd_block = pd_req->sector;
|
||||
pd_count = pd_req->current_nr_sectors;
|
||||
pd_block = blk_rq_pos(pd_req);
|
||||
pd_count = blk_rq_cur_sectors(pd_req);
|
||||
if (pd_block + pd_count > get_capacity(pd_req->rq_disk))
|
||||
return Fail;
|
||||
pd_run = pd_req->nr_sectors;
|
||||
pd_run = blk_rq_sectors(pd_req);
|
||||
pd_buf = pd_req->buffer;
|
||||
pd_retries = 0;
|
||||
if (pd_cmd == READ)
|
||||
|
|
@ -477,8 +479,8 @@ static int pd_next_buf(void)
|
|||
if (pd_count)
|
||||
return 0;
|
||||
spin_lock_irqsave(&pd_lock, saved_flags);
|
||||
end_request(pd_req, 1);
|
||||
pd_count = pd_req->current_nr_sectors;
|
||||
__blk_end_request_cur(pd_req, 0);
|
||||
pd_count = blk_rq_cur_sectors(pd_req);
|
||||
pd_buf = pd_req->buffer;
|
||||
spin_unlock_irqrestore(&pd_lock, saved_flags);
|
||||
return 0;
|
||||
|
|
@ -702,7 +704,7 @@ static void do_pd_request(struct request_queue * q)
|
|||
{
|
||||
if (pd_req)
|
||||
return;
|
||||
pd_req = elv_next_request(q);
|
||||
pd_req = blk_fetch_request(q);
|
||||
if (!pd_req)
|
||||
return;
|
||||
|
||||
|
|
|
|||
|
|
@ -750,12 +750,10 @@ static int pf_ready(void)
|
|||
|
||||
static struct request_queue *pf_queue;
|
||||
|
||||
static void pf_end_request(int uptodate)
|
||||
static void pf_end_request(int err)
|
||||
{
|
||||
if (pf_req) {
|
||||
end_request(pf_req, uptodate);
|
||||
if (pf_req && !__blk_end_request_cur(pf_req, err))
|
||||
pf_req = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_pf_request(struct request_queue * q)
|
||||
|
|
@ -763,17 +761,19 @@ static void do_pf_request(struct request_queue * q)
|
|||
if (pf_busy)
|
||||
return;
|
||||
repeat:
|
||||
pf_req = elv_next_request(q);
|
||||
if (!pf_req)
|
||||
return;
|
||||
if (!pf_req) {
|
||||
pf_req = blk_fetch_request(q);
|
||||
if (!pf_req)
|
||||
return;
|
||||
}
|
||||
|
||||
pf_current = pf_req->rq_disk->private_data;
|
||||
pf_block = pf_req->sector;
|
||||
pf_run = pf_req->nr_sectors;
|
||||
pf_count = pf_req->current_nr_sectors;
|
||||
pf_block = blk_rq_pos(pf_req);
|
||||
pf_run = blk_rq_sectors(pf_req);
|
||||
pf_count = blk_rq_cur_sectors(pf_req);
|
||||
|
||||
if (pf_block + pf_count > get_capacity(pf_req->rq_disk)) {
|
||||
pf_end_request(0);
|
||||
pf_end_request(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
|
||||
|
|
@ -788,7 +788,7 @@ repeat:
|
|||
pi_do_claimed(pf_current->pi, do_pf_write);
|
||||
else {
|
||||
pf_busy = 0;
|
||||
pf_end_request(0);
|
||||
pf_end_request(-EIO);
|
||||
goto repeat;
|
||||
}
|
||||
}
|
||||
|
|
@ -805,23 +805,22 @@ static int pf_next_buf(void)
|
|||
return 1;
|
||||
if (!pf_count) {
|
||||
spin_lock_irqsave(&pf_spin_lock, saved_flags);
|
||||
pf_end_request(1);
|
||||
pf_req = elv_next_request(pf_queue);
|
||||
pf_end_request(0);
|
||||
spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
|
||||
if (!pf_req)
|
||||
return 1;
|
||||
pf_count = pf_req->current_nr_sectors;
|
||||
pf_count = blk_rq_cur_sectors(pf_req);
|
||||
pf_buf = pf_req->buffer;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void next_request(int success)
|
||||
static inline void next_request(int err)
|
||||
{
|
||||
unsigned long saved_flags;
|
||||
|
||||
spin_lock_irqsave(&pf_spin_lock, saved_flags);
|
||||
pf_end_request(success);
|
||||
pf_end_request(err);
|
||||
pf_busy = 0;
|
||||
do_pf_request(pf_queue);
|
||||
spin_unlock_irqrestore(&pf_spin_lock, saved_flags);
|
||||
|
|
@ -844,7 +843,7 @@ static void do_pf_read_start(void)
|
|||
pi_do_claimed(pf_current->pi, do_pf_read_start);
|
||||
return;
|
||||
}
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
pf_mask = STAT_DRQ;
|
||||
|
|
@ -863,7 +862,7 @@ static void do_pf_read_drq(void)
|
|||
pi_do_claimed(pf_current->pi, do_pf_read_start);
|
||||
return;
|
||||
}
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
pi_read_block(pf_current->pi, pf_buf, 512);
|
||||
|
|
@ -871,7 +870,7 @@ static void do_pf_read_drq(void)
|
|||
break;
|
||||
}
|
||||
pi_disconnect(pf_current->pi);
|
||||
next_request(1);
|
||||
next_request(0);
|
||||
}
|
||||
|
||||
static void do_pf_write(void)
|
||||
|
|
@ -890,7 +889,7 @@ static void do_pf_write_start(void)
|
|||
pi_do_claimed(pf_current->pi, do_pf_write_start);
|
||||
return;
|
||||
}
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -903,7 +902,7 @@ static void do_pf_write_start(void)
|
|||
pi_do_claimed(pf_current->pi, do_pf_write_start);
|
||||
return;
|
||||
}
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
pi_write_block(pf_current->pi, pf_buf, 512);
|
||||
|
|
@ -923,11 +922,11 @@ static void do_pf_write_done(void)
|
|||
pi_do_claimed(pf_current->pi, do_pf_write_start);
|
||||
return;
|
||||
}
|
||||
next_request(0);
|
||||
next_request(-EIO);
|
||||
return;
|
||||
}
|
||||
pi_disconnect(pf_current->pi);
|
||||
next_request(1);
|
||||
next_request(0);
|
||||
}
|
||||
|
||||
static int __init pf_init(void)
|
||||
|
|
|
|||
|
|
@ -991,13 +991,15 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
|
|||
*/
|
||||
static int pkt_set_segment_merging(struct pktcdvd_device *pd, struct request_queue *q)
|
||||
{
|
||||
if ((pd->settings.size << 9) / CD_FRAMESIZE <= q->max_phys_segments) {
|
||||
if ((pd->settings.size << 9) / CD_FRAMESIZE
|
||||
<= queue_max_phys_segments(q)) {
|
||||
/*
|
||||
* The cdrom device can handle one segment/frame
|
||||
*/
|
||||
clear_bit(PACKET_MERGE_SEGS, &pd->flags);
|
||||
return 0;
|
||||
} else if ((pd->settings.size << 9) / PAGE_SIZE <= q->max_phys_segments) {
|
||||
} else if ((pd->settings.size << 9) / PAGE_SIZE
|
||||
<= queue_max_phys_segments(q)) {
|
||||
/*
|
||||
* We can handle this case at the expense of some extra memory
|
||||
* copies during write operations
|
||||
|
|
@ -2657,7 +2659,7 @@ static void pkt_init_queue(struct pktcdvd_device *pd)
|
|||
struct request_queue *q = pd->disk->queue;
|
||||
|
||||
blk_queue_make_request(q, pkt_make_request);
|
||||
blk_queue_hardsect_size(q, CD_FRAMESIZE);
|
||||
blk_queue_logical_block_size(q, CD_FRAMESIZE);
|
||||
blk_queue_max_sectors(q, PACKET_MAX_SECTORS);
|
||||
blk_queue_merge_bvec(q, pkt_merge_bvec);
|
||||
q->queuedata = pd;
|
||||
|
|
|
|||
|
|
@ -134,13 +134,12 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
|
|||
rq_for_each_segment(bv, req, iter)
|
||||
n++;
|
||||
dev_dbg(&dev->sbd.core,
|
||||
"%s:%u: %s req has %u bvecs for %lu sectors %lu hard sectors\n",
|
||||
__func__, __LINE__, op, n, req->nr_sectors,
|
||||
req->hard_nr_sectors);
|
||||
"%s:%u: %s req has %u bvecs for %u sectors\n",
|
||||
__func__, __LINE__, op, n, blk_rq_sectors(req));
|
||||
#endif
|
||||
|
||||
start_sector = req->sector * priv->blocking_factor;
|
||||
sectors = req->nr_sectors * priv->blocking_factor;
|
||||
start_sector = blk_rq_pos(req) * priv->blocking_factor;
|
||||
sectors = blk_rq_sectors(req) * priv->blocking_factor;
|
||||
dev_dbg(&dev->sbd.core, "%s:%u: %s %llu sectors starting at %llu\n",
|
||||
__func__, __LINE__, op, sectors, start_sector);
|
||||
|
||||
|
|
@ -158,7 +157,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
|
|||
if (res) {
|
||||
dev_err(&dev->sbd.core, "%s:%u: %s failed %d\n", __func__,
|
||||
__LINE__, op, res);
|
||||
end_request(req, 0);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -180,7 +179,7 @@ static int ps3disk_submit_flush_request(struct ps3_storage_device *dev,
|
|||
if (res) {
|
||||
dev_err(&dev->sbd.core, "%s:%u: sync cache failed 0x%llx\n",
|
||||
__func__, __LINE__, res);
|
||||
end_request(req, 0);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +194,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
|
|||
|
||||
dev_dbg(&dev->sbd.core, "%s:%u\n", __func__, __LINE__);
|
||||
|
||||
while ((req = elv_next_request(q))) {
|
||||
while ((req = blk_fetch_request(q))) {
|
||||
if (blk_fs_request(req)) {
|
||||
if (ps3disk_submit_request_sg(dev, req))
|
||||
break;
|
||||
|
|
@ -205,7 +204,7 @@ static void ps3disk_do_request(struct ps3_storage_device *dev,
|
|||
break;
|
||||
} else {
|
||||
blk_dump_rq_flags(req, DEVICE_NAME " bad request");
|
||||
end_request(req, 0);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
|
@ -231,7 +230,6 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
|
|||
struct request *req;
|
||||
int res, read, error;
|
||||
u64 tag, status;
|
||||
unsigned long num_sectors;
|
||||
const char *op;
|
||||
|
||||
res = lv1_storage_get_async_status(dev->sbd.dev_id, &tag, &status);
|
||||
|
|
@ -261,11 +259,9 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
|
|||
if (req->cmd_type == REQ_TYPE_LINUX_BLOCK &&
|
||||
req->cmd[0] == REQ_LB_OP_FLUSH) {
|
||||
read = 0;
|
||||
num_sectors = req->hard_cur_sectors;
|
||||
op = "flush";
|
||||
} else {
|
||||
read = !rq_data_dir(req);
|
||||
num_sectors = req->nr_sectors;
|
||||
op = read ? "read" : "write";
|
||||
}
|
||||
if (status) {
|
||||
|
|
@ -281,7 +277,7 @@ static irqreturn_t ps3disk_interrupt(int irq, void *data)
|
|||
}
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
__blk_end_request(req, error, num_sectors << 9);
|
||||
__blk_end_request_all(req, error);
|
||||
priv->req = NULL;
|
||||
ps3disk_do_request(dev, priv->queue);
|
||||
spin_unlock(&priv->lock);
|
||||
|
|
@ -481,7 +477,7 @@ static int __devinit ps3disk_probe(struct ps3_system_bus_device *_dev)
|
|||
blk_queue_max_sectors(queue, dev->bounce_size >> 9);
|
||||
blk_queue_segment_boundary(queue, -1UL);
|
||||
blk_queue_dma_alignment(queue, dev->blk_size-1);
|
||||
blk_queue_hardsect_size(queue, dev->blk_size);
|
||||
blk_queue_logical_block_size(queue, dev->blk_size);
|
||||
|
||||
blk_queue_ordered(queue, QUEUE_ORDERED_DRAIN_FLUSH,
|
||||
ps3disk_prepare_flush);
|
||||
|
|
|
|||
|
|
@ -212,11 +212,6 @@ static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc)
|
|||
vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD);
|
||||
}
|
||||
|
||||
static void vdc_end_request(struct request *req, int error, int num_sectors)
|
||||
{
|
||||
__blk_end_request(req, error, num_sectors << 9);
|
||||
}
|
||||
|
||||
static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
|
||||
unsigned int index)
|
||||
{
|
||||
|
|
@ -239,7 +234,7 @@ static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr,
|
|||
|
||||
rqe->req = NULL;
|
||||
|
||||
vdc_end_request(req, (desc->status ? -EIO : 0), desc->size >> 9);
|
||||
__blk_end_request(req, (desc->status ? -EIO : 0), desc->size);
|
||||
|
||||
if (blk_queue_stopped(port->disk->queue))
|
||||
blk_start_queue(port->disk->queue);
|
||||
|
|
@ -421,7 +416,7 @@ static int __send_request(struct request *req)
|
|||
desc->slice = 0;
|
||||
}
|
||||
desc->status = ~0;
|
||||
desc->offset = (req->sector << 9) / port->vdisk_block_size;
|
||||
desc->offset = (blk_rq_pos(req) << 9) / port->vdisk_block_size;
|
||||
desc->size = len;
|
||||
desc->ncookies = err;
|
||||
|
||||
|
|
@ -446,14 +441,13 @@ out:
|
|||
static void do_vdc_request(struct request_queue *q)
|
||||
{
|
||||
while (1) {
|
||||
struct request *req = elv_next_request(q);
|
||||
struct request *req = blk_fetch_request(q);
|
||||
|
||||
if (!req)
|
||||
break;
|
||||
|
||||
blkdev_dequeue_request(req);
|
||||
if (__send_request(req) < 0)
|
||||
vdc_end_request(req, -EIO, req->hard_nr_sectors);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ static int floppy_read_sectors(struct floppy_state *fs,
|
|||
ret = swim_read_sector(fs, side, track, sector,
|
||||
buffer);
|
||||
if (try-- == 0)
|
||||
return -1;
|
||||
return -EIO;
|
||||
} while (ret != 512);
|
||||
|
||||
buffer += ret;
|
||||
|
|
@ -528,45 +528,31 @@ static void redo_fd_request(struct request_queue *q)
|
|||
struct request *req;
|
||||
struct floppy_state *fs;
|
||||
|
||||
while ((req = elv_next_request(q))) {
|
||||
req = blk_fetch_request(q);
|
||||
while (req) {
|
||||
int err = -EIO;
|
||||
|
||||
fs = req->rq_disk->private_data;
|
||||
if (req->sector < 0 || req->sector >= fs->total_secs) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
if (req->current_nr_sectors == 0) {
|
||||
end_request(req, 1);
|
||||
continue;
|
||||
}
|
||||
if (!fs->disk_in) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
if (rq_data_dir(req) == WRITE) {
|
||||
if (fs->write_protected) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (blk_rq_pos(req) >= fs->total_secs)
|
||||
goto done;
|
||||
if (!fs->disk_in)
|
||||
goto done;
|
||||
if (rq_data_dir(req) == WRITE && fs->write_protected)
|
||||
goto done;
|
||||
|
||||
switch (rq_data_dir(req)) {
|
||||
case WRITE:
|
||||
/* NOT IMPLEMENTED */
|
||||
end_request(req, 0);
|
||||
break;
|
||||
case READ:
|
||||
if (floppy_read_sectors(fs, req->sector,
|
||||
req->current_nr_sectors,
|
||||
req->buffer)) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
req->nr_sectors -= req->current_nr_sectors;
|
||||
req->sector += req->current_nr_sectors;
|
||||
req->buffer += req->current_nr_sectors * 512;
|
||||
end_request(req, 1);
|
||||
err = floppy_read_sectors(fs, blk_rq_pos(req),
|
||||
blk_rq_cur_sectors(req),
|
||||
req->buffer);
|
||||
break;
|
||||
}
|
||||
done:
|
||||
if (!__blk_end_request_cur(req, err))
|
||||
req = blk_fetch_request(q);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -251,6 +251,20 @@ static int floppy_release(struct gendisk *disk, fmode_t mode);
|
|||
static int floppy_check_change(struct gendisk *disk);
|
||||
static int floppy_revalidate(struct gendisk *disk);
|
||||
|
||||
static bool swim3_end_request(int err, unsigned int nr_bytes)
|
||||
{
|
||||
if (__blk_end_request(fd_req, err, nr_bytes))
|
||||
return true;
|
||||
|
||||
fd_req = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool swim3_end_request_cur(int err)
|
||||
{
|
||||
return swim3_end_request(err, blk_rq_cur_bytes(fd_req));
|
||||
}
|
||||
|
||||
static void swim3_select(struct floppy_state *fs, int sel)
|
||||
{
|
||||
struct swim3 __iomem *sw = fs->swim3;
|
||||
|
|
@ -310,25 +324,27 @@ static void start_request(struct floppy_state *fs)
|
|||
wake_up(&fs->wait);
|
||||
return;
|
||||
}
|
||||
while (fs->state == idle && (req = elv_next_request(swim3_queue))) {
|
||||
while (fs->state == idle) {
|
||||
if (!fd_req) {
|
||||
fd_req = blk_fetch_request(swim3_queue);
|
||||
if (!fd_req)
|
||||
break;
|
||||
}
|
||||
req = fd_req;
|
||||
#if 0
|
||||
printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%ld buf=%p\n",
|
||||
printk("do_fd_req: dev=%s cmd=%d sec=%ld nr_sec=%u buf=%p\n",
|
||||
req->rq_disk->disk_name, req->cmd,
|
||||
(long)req->sector, req->nr_sectors, req->buffer);
|
||||
printk(" errors=%d current_nr_sectors=%ld\n",
|
||||
req->errors, req->current_nr_sectors);
|
||||
(long)blk_rq_pos(req), blk_rq_sectors(req), req->buffer);
|
||||
printk(" errors=%d current_nr_sectors=%u\n",
|
||||
req->errors, blk_rq_cur_sectors(req));
|
||||
#endif
|
||||
|
||||
if (req->sector < 0 || req->sector >= fs->total_secs) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
if (req->current_nr_sectors == 0) {
|
||||
end_request(req, 1);
|
||||
if (blk_rq_pos(req) >= fs->total_secs) {
|
||||
swim3_end_request_cur(-EIO);
|
||||
continue;
|
||||
}
|
||||
if (fs->ejected) {
|
||||
end_request(req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -336,18 +352,19 @@ static void start_request(struct floppy_state *fs)
|
|||
if (fs->write_prot < 0)
|
||||
fs->write_prot = swim3_readbit(fs, WRITE_PROT);
|
||||
if (fs->write_prot) {
|
||||
end_request(req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do not remove the cast. req->sector is now a sector_t and
|
||||
* can be 64 bits, but it will never go past 32 bits for this
|
||||
* driver anyway, so we can safely cast it down and not have
|
||||
* to do a 64/32 division
|
||||
/* Do not remove the cast. blk_rq_pos(req) is now a
|
||||
* sector_t and can be 64 bits, but it will never go
|
||||
* past 32 bits for this driver anyway, so we can
|
||||
* safely cast it down and not have to do a 64/32
|
||||
* division
|
||||
*/
|
||||
fs->req_cyl = ((long)req->sector) / fs->secpercyl;
|
||||
x = ((long)req->sector) % fs->secpercyl;
|
||||
fs->req_cyl = ((long)blk_rq_pos(req)) / fs->secpercyl;
|
||||
x = ((long)blk_rq_pos(req)) % fs->secpercyl;
|
||||
fs->head = x / fs->secpertrack;
|
||||
fs->req_sector = x % fs->secpertrack + 1;
|
||||
fd_req = req;
|
||||
|
|
@ -424,7 +441,7 @@ static inline void setup_transfer(struct floppy_state *fs)
|
|||
struct dbdma_cmd *cp = fs->dma_cmd;
|
||||
struct dbdma_regs __iomem *dr = fs->dma;
|
||||
|
||||
if (fd_req->current_nr_sectors <= 0) {
|
||||
if (blk_rq_cur_sectors(fd_req) <= 0) {
|
||||
printk(KERN_ERR "swim3: transfer 0 sectors?\n");
|
||||
return;
|
||||
}
|
||||
|
|
@ -432,8 +449,8 @@ static inline void setup_transfer(struct floppy_state *fs)
|
|||
n = 1;
|
||||
else {
|
||||
n = fs->secpertrack - fs->req_sector + 1;
|
||||
if (n > fd_req->current_nr_sectors)
|
||||
n = fd_req->current_nr_sectors;
|
||||
if (n > blk_rq_cur_sectors(fd_req))
|
||||
n = blk_rq_cur_sectors(fd_req);
|
||||
}
|
||||
fs->scount = n;
|
||||
swim3_select(fs, fs->head? READ_DATA_1: READ_DATA_0);
|
||||
|
|
@ -508,7 +525,7 @@ static void act(struct floppy_state *fs)
|
|||
case do_transfer:
|
||||
if (fs->cur_cyl != fs->req_cyl) {
|
||||
if (fs->retries > 5) {
|
||||
end_request(fd_req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
return;
|
||||
}
|
||||
|
|
@ -540,7 +557,7 @@ static void scan_timeout(unsigned long data)
|
|||
out_8(&sw->intr_enable, 0);
|
||||
fs->cur_cyl = -1;
|
||||
if (fs->retries > 5) {
|
||||
end_request(fd_req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
start_request(fs);
|
||||
} else {
|
||||
|
|
@ -559,7 +576,7 @@ static void seek_timeout(unsigned long data)
|
|||
out_8(&sw->select, RELAX);
|
||||
out_8(&sw->intr_enable, 0);
|
||||
printk(KERN_ERR "swim3: seek timeout\n");
|
||||
end_request(fd_req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
start_request(fs);
|
||||
}
|
||||
|
|
@ -583,7 +600,7 @@ static void settle_timeout(unsigned long data)
|
|||
return;
|
||||
}
|
||||
printk(KERN_ERR "swim3: seek settle timeout\n");
|
||||
end_request(fd_req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
start_request(fs);
|
||||
}
|
||||
|
|
@ -593,8 +610,6 @@ static void xfer_timeout(unsigned long data)
|
|||
struct floppy_state *fs = (struct floppy_state *) data;
|
||||
struct swim3 __iomem *sw = fs->swim3;
|
||||
struct dbdma_regs __iomem *dr = fs->dma;
|
||||
struct dbdma_cmd *cp = fs->dma_cmd;
|
||||
unsigned long s;
|
||||
int n;
|
||||
|
||||
fs->timeout_pending = 0;
|
||||
|
|
@ -605,17 +620,10 @@ static void xfer_timeout(unsigned long data)
|
|||
out_8(&sw->intr_enable, 0);
|
||||
out_8(&sw->control_bic, WRITE_SECTORS | DO_ACTION);
|
||||
out_8(&sw->select, RELAX);
|
||||
if (rq_data_dir(fd_req) == WRITE)
|
||||
++cp;
|
||||
if (ld_le16(&cp->xfer_status) != 0)
|
||||
s = fs->scount - ((ld_le16(&cp->res_count) + 511) >> 9);
|
||||
else
|
||||
s = 0;
|
||||
fd_req->sector += s;
|
||||
fd_req->current_nr_sectors -= s;
|
||||
printk(KERN_ERR "swim3: timeout %sing sector %ld\n",
|
||||
(rq_data_dir(fd_req)==WRITE? "writ": "read"), (long)fd_req->sector);
|
||||
end_request(fd_req, 0);
|
||||
(rq_data_dir(fd_req)==WRITE? "writ": "read"),
|
||||
(long)blk_rq_pos(fd_req));
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
start_request(fs);
|
||||
}
|
||||
|
|
@ -646,7 +654,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
|
|||
printk(KERN_ERR "swim3: seen sector but cyl=ff?\n");
|
||||
fs->cur_cyl = -1;
|
||||
if (fs->retries > 5) {
|
||||
end_request(fd_req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
start_request(fs);
|
||||
} else {
|
||||
|
|
@ -719,9 +727,7 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
|
|||
if (intr & ERROR_INTR) {
|
||||
n = fs->scount - 1 - resid / 512;
|
||||
if (n > 0) {
|
||||
fd_req->sector += n;
|
||||
fd_req->current_nr_sectors -= n;
|
||||
fd_req->buffer += n * 512;
|
||||
blk_update_request(fd_req, 0, n << 9);
|
||||
fs->req_sector += n;
|
||||
}
|
||||
if (fs->retries < 5) {
|
||||
|
|
@ -730,8 +736,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
|
|||
} else {
|
||||
printk("swim3: error %sing block %ld (err=%x)\n",
|
||||
rq_data_dir(fd_req) == WRITE? "writ": "read",
|
||||
(long)fd_req->sector, err);
|
||||
end_request(fd_req, 0);
|
||||
(long)blk_rq_pos(fd_req), err);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -740,18 +746,12 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
|
|||
printk(KERN_ERR "swim3: fd dma: stat=%x resid=%d\n", stat, resid);
|
||||
printk(KERN_ERR " state=%d, dir=%x, intr=%x, err=%x\n",
|
||||
fs->state, rq_data_dir(fd_req), intr, err);
|
||||
end_request(fd_req, 0);
|
||||
swim3_end_request_cur(-EIO);
|
||||
fs->state = idle;
|
||||
start_request(fs);
|
||||
break;
|
||||
}
|
||||
fd_req->sector += fs->scount;
|
||||
fd_req->current_nr_sectors -= fs->scount;
|
||||
fd_req->buffer += fs->scount * 512;
|
||||
if (fd_req->current_nr_sectors <= 0) {
|
||||
end_request(fd_req, 1);
|
||||
fs->state = idle;
|
||||
} else {
|
||||
if (swim3_end_request(0, fs->scount << 9)) {
|
||||
fs->req_sector += fs->scount;
|
||||
if (fs->req_sector > fs->secpertrack) {
|
||||
fs->req_sector -= fs->secpertrack;
|
||||
|
|
@ -761,7 +761,8 @@ static irqreturn_t swim3_interrupt(int irq, void *dev_id)
|
|||
}
|
||||
}
|
||||
act(fs);
|
||||
}
|
||||
} else
|
||||
fs->state = idle;
|
||||
}
|
||||
if (fs->state == idle)
|
||||
start_request(fs);
|
||||
|
|
|
|||
|
|
@ -749,8 +749,7 @@ static inline void carm_end_request_queued(struct carm_host *host,
|
|||
struct request *req = crq->rq;
|
||||
int rc;
|
||||
|
||||
rc = __blk_end_request(req, error, blk_rq_bytes(req));
|
||||
assert(rc == 0);
|
||||
__blk_end_request_all(req, error);
|
||||
|
||||
rc = carm_put_request(host, crq);
|
||||
assert(rc == 0);
|
||||
|
|
@ -811,12 +810,10 @@ static void carm_oob_rq_fn(struct request_queue *q)
|
|||
|
||||
while (1) {
|
||||
DPRINTK("get req\n");
|
||||
rq = elv_next_request(q);
|
||||
rq = blk_fetch_request(q);
|
||||
if (!rq)
|
||||
break;
|
||||
|
||||
blkdev_dequeue_request(rq);
|
||||
|
||||
crq = rq->special;
|
||||
assert(crq != NULL);
|
||||
assert(crq->rq == rq);
|
||||
|
|
@ -847,7 +844,7 @@ static void carm_rq_fn(struct request_queue *q)
|
|||
|
||||
queue_one_request:
|
||||
VPRINTK("get req\n");
|
||||
rq = elv_next_request(q);
|
||||
rq = blk_peek_request(q);
|
||||
if (!rq)
|
||||
return;
|
||||
|
||||
|
|
@ -858,7 +855,7 @@ queue_one_request:
|
|||
}
|
||||
crq->rq = rq;
|
||||
|
||||
blkdev_dequeue_request(rq);
|
||||
blk_start_request(rq);
|
||||
|
||||
if (rq_data_dir(rq) == WRITE) {
|
||||
writing = 1;
|
||||
|
|
@ -904,10 +901,10 @@ queue_one_request:
|
|||
msg->sg_count = n_elem;
|
||||
msg->sg_type = SGT_32BIT;
|
||||
msg->handle = cpu_to_le32(TAG_ENCODE(crq->tag));
|
||||
msg->lba = cpu_to_le32(rq->sector & 0xffffffff);
|
||||
tmp = (rq->sector >> 16) >> 16;
|
||||
msg->lba = cpu_to_le32(blk_rq_pos(rq) & 0xffffffff);
|
||||
tmp = (blk_rq_pos(rq) >> 16) >> 16;
|
||||
msg->lba_high = cpu_to_le16( (u16) tmp );
|
||||
msg->lba_count = cpu_to_le16(rq->nr_sectors);
|
||||
msg->lba_count = cpu_to_le16(blk_rq_sectors(rq));
|
||||
|
||||
msg_size = sizeof(struct carm_msg_rw) - sizeof(msg->sg);
|
||||
for (i = 0; i < n_elem; i++) {
|
||||
|
|
|
|||
|
|
@ -360,8 +360,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
|||
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_scsi_cmd *cmd, struct ub_request *urq);
|
||||
static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
||||
static void ub_end_rq(struct request *rq, unsigned int status,
|
||||
unsigned int cmd_len);
|
||||
static void ub_end_rq(struct request *rq, unsigned int status);
|
||||
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
|
||||
struct ub_request *urq, struct ub_scsi_cmd *cmd);
|
||||
static int ub_submit_scsi(struct ub_dev *sc, struct ub_scsi_cmd *cmd);
|
||||
|
|
@ -627,7 +626,7 @@ static void ub_request_fn(struct request_queue *q)
|
|||
struct ub_lun *lun = q->queuedata;
|
||||
struct request *rq;
|
||||
|
||||
while ((rq = elv_next_request(q)) != NULL) {
|
||||
while ((rq = blk_peek_request(q)) != NULL) {
|
||||
if (ub_request_fn_1(lun, rq) != 0) {
|
||||
blk_stop_queue(q);
|
||||
break;
|
||||
|
|
@ -643,14 +642,14 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
|||
int n_elem;
|
||||
|
||||
if (atomic_read(&sc->poison)) {
|
||||
blkdev_dequeue_request(rq);
|
||||
ub_end_rq(rq, DID_NO_CONNECT << 16, blk_rq_bytes(rq));
|
||||
blk_start_request(rq);
|
||||
ub_end_rq(rq, DID_NO_CONNECT << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lun->changed && !blk_pc_request(rq)) {
|
||||
blkdev_dequeue_request(rq);
|
||||
ub_end_rq(rq, SAM_STAT_CHECK_CONDITION, blk_rq_bytes(rq));
|
||||
blk_start_request(rq);
|
||||
ub_end_rq(rq, SAM_STAT_CHECK_CONDITION);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -660,7 +659,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
|||
return -1;
|
||||
memset(cmd, 0, sizeof(struct ub_scsi_cmd));
|
||||
|
||||
blkdev_dequeue_request(rq);
|
||||
blk_start_request(rq);
|
||||
|
||||
urq = &lun->urq;
|
||||
memset(urq, 0, sizeof(struct ub_request));
|
||||
|
|
@ -702,7 +701,7 @@ static int ub_request_fn_1(struct ub_lun *lun, struct request *rq)
|
|||
|
||||
drop:
|
||||
ub_put_cmd(lun, cmd);
|
||||
ub_end_rq(rq, DID_ERROR << 16, blk_rq_bytes(rq));
|
||||
ub_end_rq(rq, DID_ERROR << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -723,11 +722,11 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
|||
/*
|
||||
* build the command
|
||||
*
|
||||
* The call to blk_queue_hardsect_size() guarantees that request
|
||||
* The call to blk_queue_logical_block_size() guarantees that request
|
||||
* is aligned, but it is given in terms of 512 byte units, always.
|
||||
*/
|
||||
block = rq->sector >> lun->capacity.bshift;
|
||||
nblks = rq->nr_sectors >> lun->capacity.bshift;
|
||||
block = blk_rq_pos(rq) >> lun->capacity.bshift;
|
||||
nblks = blk_rq_sectors(rq) >> lun->capacity.bshift;
|
||||
|
||||
cmd->cdb[0] = (cmd->dir == UB_DIR_READ)? READ_10: WRITE_10;
|
||||
/* 10-byte uses 4 bytes of LBA: 2147483648KB, 2097152MB, 2048GB */
|
||||
|
|
@ -739,7 +738,7 @@ static void ub_cmd_build_block(struct ub_dev *sc, struct ub_lun *lun,
|
|||
cmd->cdb[8] = nblks;
|
||||
cmd->cdb_len = 10;
|
||||
|
||||
cmd->len = rq->nr_sectors * 512;
|
||||
cmd->len = blk_rq_bytes(rq);
|
||||
}
|
||||
|
||||
static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
||||
|
|
@ -747,7 +746,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
|||
{
|
||||
struct request *rq = urq->rq;
|
||||
|
||||
if (rq->data_len == 0) {
|
||||
if (blk_rq_bytes(rq) == 0) {
|
||||
cmd->dir = UB_DIR_NONE;
|
||||
} else {
|
||||
if (rq_data_dir(rq) == WRITE)
|
||||
|
|
@ -762,7 +761,7 @@ static void ub_cmd_build_packet(struct ub_dev *sc, struct ub_lun *lun,
|
|||
memcpy(&cmd->cdb, rq->cmd, rq->cmd_len);
|
||||
cmd->cdb_len = rq->cmd_len;
|
||||
|
||||
cmd->len = rq->data_len;
|
||||
cmd->len = blk_rq_bytes(rq);
|
||||
|
||||
/*
|
||||
* To reapply this to every URB is not as incorrect as it looks.
|
||||
|
|
@ -777,16 +776,15 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|||
struct ub_request *urq = cmd->back;
|
||||
struct request *rq;
|
||||
unsigned int scsi_status;
|
||||
unsigned int cmd_len;
|
||||
|
||||
rq = urq->rq;
|
||||
|
||||
if (cmd->error == 0) {
|
||||
if (blk_pc_request(rq)) {
|
||||
if (cmd->act_len >= rq->data_len)
|
||||
rq->data_len = 0;
|
||||
if (cmd->act_len >= rq->resid_len)
|
||||
rq->resid_len = 0;
|
||||
else
|
||||
rq->data_len -= cmd->act_len;
|
||||
rq->resid_len -= cmd->act_len;
|
||||
scsi_status = 0;
|
||||
} else {
|
||||
if (cmd->act_len != cmd->len) {
|
||||
|
|
@ -818,17 +816,14 @@ static void ub_rw_cmd_done(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
|
|||
|
||||
urq->rq = NULL;
|
||||
|
||||
cmd_len = cmd->len;
|
||||
ub_put_cmd(lun, cmd);
|
||||
ub_end_rq(rq, scsi_status, cmd_len);
|
||||
ub_end_rq(rq, scsi_status);
|
||||
blk_start_queue(lun->disk->queue);
|
||||
}
|
||||
|
||||
static void ub_end_rq(struct request *rq, unsigned int scsi_status,
|
||||
unsigned int cmd_len)
|
||||
static void ub_end_rq(struct request *rq, unsigned int scsi_status)
|
||||
{
|
||||
int error;
|
||||
long rqlen;
|
||||
|
||||
if (scsi_status == 0) {
|
||||
error = 0;
|
||||
|
|
@ -836,12 +831,7 @@ static void ub_end_rq(struct request *rq, unsigned int scsi_status,
|
|||
error = -EIO;
|
||||
rq->errors = scsi_status;
|
||||
}
|
||||
rqlen = blk_rq_bytes(rq); /* Oddly enough, this is the residue. */
|
||||
if (__blk_end_request(rq, error, cmd_len)) {
|
||||
printk(KERN_WARNING DRV_NAME
|
||||
": __blk_end_request blew, %s-cmd total %u rqlen %ld\n",
|
||||
blk_pc_request(rq)? "pc": "fs", cmd_len, rqlen);
|
||||
}
|
||||
__blk_end_request_all(rq, error);
|
||||
}
|
||||
|
||||
static int ub_rw_cmd_retry(struct ub_dev *sc, struct ub_lun *lun,
|
||||
|
|
@ -1759,7 +1749,7 @@ static int ub_bd_revalidate(struct gendisk *disk)
|
|||
ub_revalidate(lun->udev, lun);
|
||||
|
||||
/* XXX Support sector size switching like in sr.c */
|
||||
blk_queue_hardsect_size(disk->queue, lun->capacity.bsize);
|
||||
blk_queue_logical_block_size(disk->queue, lun->capacity.bsize);
|
||||
set_capacity(disk, lun->capacity.nsec);
|
||||
// set_disk_ro(sdkp->disk, lun->readonly);
|
||||
|
||||
|
|
@ -2334,7 +2324,7 @@ static int ub_probe_lun(struct ub_dev *sc, int lnum)
|
|||
blk_queue_max_phys_segments(q, UB_MAX_REQ_SG);
|
||||
blk_queue_segment_boundary(q, 0xffffffff); /* Dubious. */
|
||||
blk_queue_max_sectors(q, UB_MAX_SECTORS);
|
||||
blk_queue_hardsect_size(q, lun->capacity.bsize);
|
||||
blk_queue_logical_block_size(q, lun->capacity.bsize);
|
||||
|
||||
lun->disk = disk;
|
||||
q->queuedata = lun;
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ static int send_request(struct request *req)
|
|||
struct viodasd_device *d;
|
||||
unsigned long flags;
|
||||
|
||||
start = (u64)req->sector << 9;
|
||||
start = (u64)blk_rq_pos(req) << 9;
|
||||
|
||||
if (rq_data_dir(req) == READ) {
|
||||
direction = DMA_FROM_DEVICE;
|
||||
|
|
@ -361,19 +361,17 @@ static void do_viodasd_request(struct request_queue *q)
|
|||
* back later.
|
||||
*/
|
||||
while (num_req_outstanding < VIOMAXREQ) {
|
||||
req = elv_next_request(q);
|
||||
req = blk_fetch_request(q);
|
||||
if (req == NULL)
|
||||
return;
|
||||
/* dequeue the current request from the queue */
|
||||
blkdev_dequeue_request(req);
|
||||
/* check that request contains a valid command */
|
||||
if (!blk_fs_request(req)) {
|
||||
viodasd_end_request(req, -EIO, req->hard_nr_sectors);
|
||||
viodasd_end_request(req, -EIO, blk_rq_sectors(req));
|
||||
continue;
|
||||
}
|
||||
/* Try sending the request */
|
||||
if (send_request(req) != 0)
|
||||
viodasd_end_request(req, -EIO, req->hard_nr_sectors);
|
||||
viodasd_end_request(req, -EIO, blk_rq_sectors(req));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -590,7 +588,7 @@ static int viodasd_handle_read_write(struct vioblocklpevent *bevent)
|
|||
err = vio_lookup_rc(viodasd_err_table, bevent->sub_result);
|
||||
printk(VIOD_KERN_WARNING "read/write error %d:0x%04x (%s)\n",
|
||||
event->xRc, bevent->sub_result, err->msg);
|
||||
num_sect = req->hard_nr_sectors;
|
||||
num_sect = blk_rq_sectors(req);
|
||||
}
|
||||
qlock = req->q->queue_lock;
|
||||
spin_lock_irqsave(qlock, irq_flags);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ struct virtblk_req
|
|||
struct list_head list;
|
||||
struct request *req;
|
||||
struct virtio_blk_outhdr out_hdr;
|
||||
struct virtio_scsi_inhdr in_hdr;
|
||||
u8 status;
|
||||
};
|
||||
|
||||
|
|
@ -50,6 +51,7 @@ static void blk_done(struct virtqueue *vq)
|
|||
spin_lock_irqsave(&vblk->lock, flags);
|
||||
while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
|
||||
int error;
|
||||
|
||||
switch (vbr->status) {
|
||||
case VIRTIO_BLK_S_OK:
|
||||
error = 0;
|
||||
|
|
@ -62,7 +64,13 @@ static void blk_done(struct virtqueue *vq)
|
|||
break;
|
||||
}
|
||||
|
||||
__blk_end_request(vbr->req, error, blk_rq_bytes(vbr->req));
|
||||
if (blk_pc_request(vbr->req)) {
|
||||
vbr->req->resid_len = vbr->in_hdr.residual;
|
||||
vbr->req->sense_len = vbr->in_hdr.sense_len;
|
||||
vbr->req->errors = vbr->in_hdr.errors;
|
||||
}
|
||||
|
||||
__blk_end_request_all(vbr->req, error);
|
||||
list_del(&vbr->list);
|
||||
mempool_free(vbr, vblk->pool);
|
||||
}
|
||||
|
|
@ -74,7 +82,7 @@ static void blk_done(struct virtqueue *vq)
|
|||
static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
||||
struct request *req)
|
||||
{
|
||||
unsigned long num, out, in;
|
||||
unsigned long num, out = 0, in = 0;
|
||||
struct virtblk_req *vbr;
|
||||
|
||||
vbr = mempool_alloc(vblk->pool, GFP_ATOMIC);
|
||||
|
|
@ -85,7 +93,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
|||
vbr->req = req;
|
||||
if (blk_fs_request(vbr->req)) {
|
||||
vbr->out_hdr.type = 0;
|
||||
vbr->out_hdr.sector = vbr->req->sector;
|
||||
vbr->out_hdr.sector = blk_rq_pos(vbr->req);
|
||||
vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
|
||||
} else if (blk_pc_request(vbr->req)) {
|
||||
vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
|
||||
|
|
@ -99,18 +107,36 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
|||
if (blk_barrier_rq(vbr->req))
|
||||
vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
|
||||
|
||||
sg_set_buf(&vblk->sg[0], &vbr->out_hdr, sizeof(vbr->out_hdr));
|
||||
num = blk_rq_map_sg(q, vbr->req, vblk->sg+1);
|
||||
sg_set_buf(&vblk->sg[num+1], &vbr->status, sizeof(vbr->status));
|
||||
sg_set_buf(&vblk->sg[out++], &vbr->out_hdr, sizeof(vbr->out_hdr));
|
||||
|
||||
if (rq_data_dir(vbr->req) == WRITE) {
|
||||
vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
|
||||
out = 1 + num;
|
||||
in = 1;
|
||||
} else {
|
||||
vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
|
||||
out = 1;
|
||||
in = 1 + num;
|
||||
/*
|
||||
* If this is a packet command we need a couple of additional headers.
|
||||
* Behind the normal outhdr we put a segment with the scsi command
|
||||
* block, and before the normal inhdr we put the sense data and the
|
||||
* inhdr with additional status information before the normal inhdr.
|
||||
*/
|
||||
if (blk_pc_request(vbr->req))
|
||||
sg_set_buf(&vblk->sg[out++], vbr->req->cmd, vbr->req->cmd_len);
|
||||
|
||||
num = blk_rq_map_sg(q, vbr->req, vblk->sg + out);
|
||||
|
||||
if (blk_pc_request(vbr->req)) {
|
||||
sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96);
|
||||
sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr,
|
||||
sizeof(vbr->in_hdr));
|
||||
}
|
||||
|
||||
sg_set_buf(&vblk->sg[num + out + in++], &vbr->status,
|
||||
sizeof(vbr->status));
|
||||
|
||||
if (num) {
|
||||
if (rq_data_dir(vbr->req) == WRITE) {
|
||||
vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
|
||||
out += num;
|
||||
} else {
|
||||
vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
|
||||
in += num;
|
||||
}
|
||||
}
|
||||
|
||||
if (vblk->vq->vq_ops->add_buf(vblk->vq, vblk->sg, out, in, vbr)) {
|
||||
|
|
@ -124,12 +150,11 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
|
|||
|
||||
static void do_virtblk_request(struct request_queue *q)
|
||||
{
|
||||
struct virtio_blk *vblk = NULL;
|
||||
struct virtio_blk *vblk = q->queuedata;
|
||||
struct request *req;
|
||||
unsigned int issued = 0;
|
||||
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
vblk = req->rq_disk->private_data;
|
||||
while ((req = blk_peek_request(q)) != NULL) {
|
||||
BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems);
|
||||
|
||||
/* If this request fails, stop queue and wait for something to
|
||||
|
|
@ -138,7 +163,7 @@ static void do_virtblk_request(struct request_queue *q)
|
|||
blk_stop_queue(q);
|
||||
break;
|
||||
}
|
||||
blkdev_dequeue_request(req);
|
||||
blk_start_request(req);
|
||||
issued++;
|
||||
}
|
||||
|
||||
|
|
@ -146,12 +171,51 @@ static void do_virtblk_request(struct request_queue *q)
|
|||
vblk->vq->vq_ops->kick(vblk->vq);
|
||||
}
|
||||
|
||||
/* return ATA identify data
|
||||
*/
|
||||
static int virtblk_identify(struct gendisk *disk, void *argp)
|
||||
{
|
||||
struct virtio_blk *vblk = disk->private_data;
|
||||
void *opaque;
|
||||
int err = -ENOMEM;
|
||||
|
||||
opaque = kmalloc(VIRTIO_BLK_ID_BYTES, GFP_KERNEL);
|
||||
if (!opaque)
|
||||
goto out;
|
||||
|
||||
err = virtio_config_buf(vblk->vdev, VIRTIO_BLK_F_IDENTIFY,
|
||||
offsetof(struct virtio_blk_config, identify), opaque,
|
||||
VIRTIO_BLK_ID_BYTES);
|
||||
|
||||
if (err)
|
||||
goto out_kfree;
|
||||
|
||||
if (copy_to_user(argp, opaque, VIRTIO_BLK_ID_BYTES))
|
||||
err = -EFAULT;
|
||||
|
||||
out_kfree:
|
||||
kfree(opaque);
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned cmd, unsigned long data)
|
||||
{
|
||||
return scsi_cmd_ioctl(bdev->bd_disk->queue,
|
||||
bdev->bd_disk, mode, cmd,
|
||||
(void __user *)data);
|
||||
struct gendisk *disk = bdev->bd_disk;
|
||||
struct virtio_blk *vblk = disk->private_data;
|
||||
void __user *argp = (void __user *)data;
|
||||
|
||||
if (cmd == HDIO_GET_IDENTITY)
|
||||
return virtblk_identify(disk, argp);
|
||||
|
||||
/*
|
||||
* Only allow the generic SCSI ioctls if the host can support it.
|
||||
*/
|
||||
if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI))
|
||||
return -ENOIOCTLCMD;
|
||||
|
||||
return scsi_cmd_ioctl(disk->queue, disk, mode, cmd, argp);
|
||||
}
|
||||
|
||||
/* We provide getgeo only to please some old bootloader/partitioning tools */
|
||||
|
|
@ -249,6 +313,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
goto out_put_disk;
|
||||
}
|
||||
|
||||
vblk->disk->queue->queuedata = vblk;
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_VIRT, vblk->disk->queue);
|
||||
|
||||
if (index < 26) {
|
||||
|
|
@ -313,7 +378,7 @@ static int virtblk_probe(struct virtio_device *vdev)
|
|||
offsetof(struct virtio_blk_config, blk_size),
|
||||
&blk_size);
|
||||
if (!err)
|
||||
blk_queue_hardsect_size(vblk->disk->queue, blk_size);
|
||||
blk_queue_logical_block_size(vblk->disk->queue, blk_size);
|
||||
|
||||
add_disk(vblk->disk);
|
||||
return 0;
|
||||
|
|
@ -356,6 +421,7 @@ static struct virtio_device_id id_table[] = {
|
|||
static unsigned int features[] = {
|
||||
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
|
||||
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
|
||||
VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_IDENTIFY
|
||||
};
|
||||
|
||||
static struct virtio_driver virtio_blk = {
|
||||
|
|
|
|||
|
|
@ -305,30 +305,25 @@ static void do_xd_request (struct request_queue * q)
|
|||
if (xdc_busy)
|
||||
return;
|
||||
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
unsigned block = req->sector;
|
||||
unsigned count = req->nr_sectors;
|
||||
int rw = rq_data_dir(req);
|
||||
req = blk_fetch_request(q);
|
||||
while (req) {
|
||||
unsigned block = blk_rq_pos(req);
|
||||
unsigned count = blk_rq_cur_sectors(req);
|
||||
XD_INFO *disk = req->rq_disk->private_data;
|
||||
int res = 0;
|
||||
int res = -EIO;
|
||||
int retry;
|
||||
|
||||
if (!blk_fs_request(req)) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
if (block + count > get_capacity(req->rq_disk)) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
if (rw != READ && rw != WRITE) {
|
||||
printk("do_xd_request: unknown request\n");
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
if (!blk_fs_request(req))
|
||||
goto done;
|
||||
if (block + count > get_capacity(req->rq_disk))
|
||||
goto done;
|
||||
for (retry = 0; (retry < XD_RETRIES) && !res; retry++)
|
||||
res = xd_readwrite(rw, disk, req->buffer, block, count);
|
||||
end_request(req, res); /* wrap up, 0 = fail, 1 = success */
|
||||
res = xd_readwrite(rq_data_dir(req), disk, req->buffer,
|
||||
block, count);
|
||||
done:
|
||||
/* wrap up, 0 = success, -errno = fail */
|
||||
if (!__blk_end_request_cur(req, res))
|
||||
req = blk_fetch_request(q);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -418,7 +413,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_
|
|||
printk("xd%c: %s timeout, recalibrating drive\n",'a'+drive,(operation == READ ? "read" : "write"));
|
||||
xd_recalibrate(drive);
|
||||
spin_lock_irq(&xd_lock);
|
||||
return (0);
|
||||
return -EIO;
|
||||
case 2:
|
||||
if (sense[0] & 0x30) {
|
||||
printk("xd%c: %s - ",'a'+drive,(operation == READ ? "reading" : "writing"));
|
||||
|
|
@ -439,7 +434,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_
|
|||
else
|
||||
printk(" - no valid disk address\n");
|
||||
spin_lock_irq(&xd_lock);
|
||||
return (0);
|
||||
return -EIO;
|
||||
}
|
||||
if (xd_dma_buffer)
|
||||
for (i=0; i < (temp * 0x200); i++)
|
||||
|
|
@ -448,7 +443,7 @@ static int xd_readwrite (u_char operation,XD_INFO *p,char *buffer,u_int block,u_
|
|||
count -= temp, buffer += temp * 0x200, block += temp;
|
||||
}
|
||||
spin_lock_irq(&xd_lock);
|
||||
return (1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ static DEFINE_SPINLOCK(blkif_io_lock);
|
|||
static int get_id_from_freelist(struct blkfront_info *info)
|
||||
{
|
||||
unsigned long free = info->shadow_free;
|
||||
BUG_ON(free > BLK_RING_SIZE);
|
||||
BUG_ON(free >= BLK_RING_SIZE);
|
||||
info->shadow_free = info->shadow[free].req.id;
|
||||
info->shadow[free].req.id = 0x0fffffee; /* debug */
|
||||
return free;
|
||||
|
|
@ -231,7 +231,7 @@ static int blkif_queue_request(struct request *req)
|
|||
info->shadow[id].request = (unsigned long)req;
|
||||
|
||||
ring_req->id = id;
|
||||
ring_req->sector_number = (blkif_sector_t)req->sector;
|
||||
ring_req->sector_number = (blkif_sector_t)blk_rq_pos(req);
|
||||
ring_req->handle = info->handle;
|
||||
|
||||
ring_req->operation = rq_data_dir(req) ?
|
||||
|
|
@ -299,25 +299,25 @@ static void do_blkif_request(struct request_queue *rq)
|
|||
|
||||
queued = 0;
|
||||
|
||||
while ((req = elv_next_request(rq)) != NULL) {
|
||||
while ((req = blk_peek_request(rq)) != NULL) {
|
||||
info = req->rq_disk->private_data;
|
||||
if (!blk_fs_request(req)) {
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (RING_FULL(&info->ring))
|
||||
goto wait;
|
||||
|
||||
blk_start_request(req);
|
||||
|
||||
if (!blk_fs_request(req)) {
|
||||
__blk_end_request_all(req, -EIO);
|
||||
continue;
|
||||
}
|
||||
|
||||
pr_debug("do_blk_req %p: cmd %p, sec %lx, "
|
||||
"(%u/%li) buffer:%p [%s]\n",
|
||||
req, req->cmd, (unsigned long)req->sector,
|
||||
req->current_nr_sectors,
|
||||
req->nr_sectors, req->buffer,
|
||||
rq_data_dir(req) ? "write" : "read");
|
||||
"(%u/%u) buffer:%p [%s]\n",
|
||||
req, req->cmd, (unsigned long)blk_rq_pos(req),
|
||||
blk_rq_cur_sectors(req), blk_rq_sectors(req),
|
||||
req->buffer, rq_data_dir(req) ? "write" : "read");
|
||||
|
||||
|
||||
blkdev_dequeue_request(req);
|
||||
if (blkif_queue_request(req)) {
|
||||
blk_requeue_request(rq, req);
|
||||
wait:
|
||||
|
|
@ -344,7 +344,7 @@ static int xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
|
|||
queue_flag_set_unlocked(QUEUE_FLAG_VIRT, rq);
|
||||
|
||||
/* Hard sector size and max sectors impersonate the equiv. hardware. */
|
||||
blk_queue_hardsect_size(rq, sector_size);
|
||||
blk_queue_logical_block_size(rq, sector_size);
|
||||
blk_queue_max_sectors(rq, 512);
|
||||
|
||||
/* Each segment in a request is up to an aligned page in size. */
|
||||
|
|
@ -551,7 +551,6 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
|||
|
||||
for (i = info->ring.rsp_cons; i != rp; i++) {
|
||||
unsigned long id;
|
||||
int ret;
|
||||
|
||||
bret = RING_GET_RESPONSE(&info->ring, i);
|
||||
id = bret->id;
|
||||
|
|
@ -578,8 +577,7 @@ static irqreturn_t blkif_interrupt(int irq, void *dev_id)
|
|||
dev_dbg(&info->xbdev->dev, "Bad return from blkdev data "
|
||||
"request: %x\n", bret->status);
|
||||
|
||||
ret = __blk_end_request(req, error, blk_rq_bytes(req));
|
||||
BUG_ON(ret);
|
||||
__blk_end_request_all(req, error);
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
|
|
@ -934,8 +932,6 @@ static void blkfront_closing(struct xenbus_device *dev)
|
|||
|
||||
spin_lock_irqsave(&blkif_io_lock, flags);
|
||||
|
||||
del_gendisk(info->gd);
|
||||
|
||||
/* No more blkif_request(). */
|
||||
blk_stop_queue(info->rq);
|
||||
|
||||
|
|
@ -949,6 +945,8 @@ static void blkfront_closing(struct xenbus_device *dev)
|
|||
blk_cleanup_queue(info->rq);
|
||||
info->rq = NULL;
|
||||
|
||||
del_gendisk(info->gd);
|
||||
|
||||
out:
|
||||
xenbus_frontend_closed(dev);
|
||||
}
|
||||
|
|
@ -977,8 +975,10 @@ static void backend_changed(struct xenbus_device *dev,
|
|||
break;
|
||||
|
||||
case XenbusStateClosing:
|
||||
if (info->gd == NULL)
|
||||
xenbus_dev_fatal(dev, -ENODEV, "gd is NULL");
|
||||
if (info->gd == NULL) {
|
||||
xenbus_frontend_closed(dev);
|
||||
break;
|
||||
}
|
||||
bd = bdget_disk(info->gd, 0);
|
||||
if (bd == NULL)
|
||||
xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
|
||||
|
|
|
|||
|
|
@ -463,10 +463,11 @@ struct request *ace_get_next_request(struct request_queue * q)
|
|||
{
|
||||
struct request *req;
|
||||
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
while ((req = blk_peek_request(q)) != NULL) {
|
||||
if (blk_fs_request(req))
|
||||
break;
|
||||
end_request(req, 0);
|
||||
blk_start_request(req);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
}
|
||||
return req;
|
||||
}
|
||||
|
|
@ -492,9 +493,13 @@ static void ace_fsm_dostate(struct ace_device *ace)
|
|||
set_capacity(ace->gd, 0);
|
||||
dev_info(ace->dev, "No CF in slot\n");
|
||||
|
||||
/* Drop all pending requests */
|
||||
while ((req = elv_next_request(ace->queue)) != NULL)
|
||||
end_request(req, 0);
|
||||
/* Drop all in-flight and pending requests */
|
||||
if (ace->req) {
|
||||
__blk_end_request_all(ace->req, -EIO);
|
||||
ace->req = NULL;
|
||||
}
|
||||
while ((req = blk_fetch_request(ace->queue)) != NULL)
|
||||
__blk_end_request_all(req, -EIO);
|
||||
|
||||
/* Drop back to IDLE state and notify waiters */
|
||||
ace->fsm_state = ACE_FSM_STATE_IDLE;
|
||||
|
|
@ -642,19 +647,21 @@ static void ace_fsm_dostate(struct ace_device *ace)
|
|||
ace->fsm_state = ACE_FSM_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
blk_start_request(req);
|
||||
|
||||
/* Okay, it's a data request, set it up for transfer */
|
||||
dev_dbg(ace->dev,
|
||||
"request: sec=%llx hcnt=%lx, ccnt=%x, dir=%i\n",
|
||||
(unsigned long long) req->sector, req->hard_nr_sectors,
|
||||
req->current_nr_sectors, rq_data_dir(req));
|
||||
"request: sec=%llx hcnt=%x, ccnt=%x, dir=%i\n",
|
||||
(unsigned long long)blk_rq_pos(req),
|
||||
blk_rq_sectors(req), blk_rq_cur_sectors(req),
|
||||
rq_data_dir(req));
|
||||
|
||||
ace->req = req;
|
||||
ace->data_ptr = req->buffer;
|
||||
ace->data_count = req->current_nr_sectors * ACE_BUF_PER_SECTOR;
|
||||
ace_out32(ace, ACE_MPULBA, req->sector & 0x0FFFFFFF);
|
||||
ace->data_count = blk_rq_cur_sectors(req) * ACE_BUF_PER_SECTOR;
|
||||
ace_out32(ace, ACE_MPULBA, blk_rq_pos(req) & 0x0FFFFFFF);
|
||||
|
||||
count = req->hard_nr_sectors;
|
||||
count = blk_rq_sectors(req);
|
||||
if (rq_data_dir(req)) {
|
||||
/* Kick off write request */
|
||||
dev_dbg(ace->dev, "write data\n");
|
||||
|
|
@ -688,7 +695,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
|
|||
dev_dbg(ace->dev,
|
||||
"CFBSY set; t=%i iter=%i c=%i dc=%i irq=%i\n",
|
||||
ace->fsm_task, ace->fsm_iter_num,
|
||||
ace->req->current_nr_sectors * 16,
|
||||
blk_rq_cur_sectors(ace->req) * 16,
|
||||
ace->data_count, ace->in_irq);
|
||||
ace_fsm_yield(ace); /* need to poll CFBSY bit */
|
||||
break;
|
||||
|
|
@ -697,7 +704,7 @@ static void ace_fsm_dostate(struct ace_device *ace)
|
|||
dev_dbg(ace->dev,
|
||||
"DATABUF not set; t=%i iter=%i c=%i dc=%i irq=%i\n",
|
||||
ace->fsm_task, ace->fsm_iter_num,
|
||||
ace->req->current_nr_sectors * 16,
|
||||
blk_rq_cur_sectors(ace->req) * 16,
|
||||
ace->data_count, ace->in_irq);
|
||||
ace_fsm_yieldirq(ace);
|
||||
break;
|
||||
|
|
@ -717,14 +724,13 @@ static void ace_fsm_dostate(struct ace_device *ace)
|
|||
}
|
||||
|
||||
/* bio finished; is there another one? */
|
||||
if (__blk_end_request(ace->req, 0,
|
||||
blk_rq_cur_bytes(ace->req))) {
|
||||
/* dev_dbg(ace->dev, "next block; h=%li c=%i\n",
|
||||
* ace->req->hard_nr_sectors,
|
||||
* ace->req->current_nr_sectors);
|
||||
if (__blk_end_request_cur(ace->req, 0)) {
|
||||
/* dev_dbg(ace->dev, "next block; h=%u c=%u\n",
|
||||
* blk_rq_sectors(ace->req),
|
||||
* blk_rq_cur_sectors(ace->req));
|
||||
*/
|
||||
ace->data_ptr = ace->req->buffer;
|
||||
ace->data_count = ace->req->current_nr_sectors * 16;
|
||||
ace->data_count = blk_rq_cur_sectors(ace->req) * 16;
|
||||
ace_fsm_yieldirq(ace);
|
||||
break;
|
||||
}
|
||||
|
|
@ -978,7 +984,7 @@ static int __devinit ace_setup(struct ace_device *ace)
|
|||
ace->queue = blk_init_queue(ace_request, &ace->lock);
|
||||
if (ace->queue == NULL)
|
||||
goto err_blk_initq;
|
||||
blk_queue_hardsect_size(ace->queue, 512);
|
||||
blk_queue_logical_block_size(ace->queue, 512);
|
||||
|
||||
/*
|
||||
* Allocate and initialize GD structure
|
||||
|
|
|
|||
|
|
@ -70,15 +70,18 @@ static struct gendisk *z2ram_gendisk;
|
|||
static void do_z2_request(struct request_queue *q)
|
||||
{
|
||||
struct request *req;
|
||||
while ((req = elv_next_request(q)) != NULL) {
|
||||
unsigned long start = req->sector << 9;
|
||||
unsigned long len = req->current_nr_sectors << 9;
|
||||
|
||||
req = blk_fetch_request(q);
|
||||
while (req) {
|
||||
unsigned long start = blk_rq_pos(req) << 9;
|
||||
unsigned long len = blk_rq_cur_bytes(req);
|
||||
int err = 0;
|
||||
|
||||
if (start + len > z2ram_size) {
|
||||
printk( KERN_ERR DEVICE_NAME ": bad access: block=%lu, count=%u\n",
|
||||
req->sector, req->current_nr_sectors);
|
||||
end_request(req, 0);
|
||||
continue;
|
||||
blk_rq_pos(req), blk_rq_cur_sectors(req));
|
||||
err = -EIO;
|
||||
goto done;
|
||||
}
|
||||
while (len) {
|
||||
unsigned long addr = start & Z2RAM_CHUNKMASK;
|
||||
|
|
@ -93,7 +96,9 @@ static void do_z2_request(struct request_queue *q)
|
|||
start += size;
|
||||
len -= size;
|
||||
}
|
||||
end_request(req, 1);
|
||||
done:
|
||||
if (!__blk_end_request_cur(req, err))
|
||||
req = blk_fetch_request(q);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -277,8 +277,8 @@ static int hci_uart_tty_open(struct tty_struct *tty)
|
|||
/* FIXME: why is this needed. Note don't use ldisc_ref here as the
|
||||
open path is before the ldisc is referencable */
|
||||
|
||||
if (tty->ldisc.ops->flush_buffer)
|
||||
tty->ldisc.ops->flush_buffer(tty);
|
||||
if (tty->ldisc->ops->flush_buffer)
|
||||
tty->ldisc->ops->flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
|
||||
return 0;
|
||||
|
|
@ -463,7 +463,6 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file,
|
|||
clear_bit(HCI_UART_PROTO_SET, &hu->flags);
|
||||
return err;
|
||||
}
|
||||
tty->low_latency = 1;
|
||||
} else
|
||||
return -EBUSY;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -2101,8 +2101,8 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
|
|||
nr = nframes;
|
||||
if (cdi->cdda_method == CDDA_BPC_SINGLE)
|
||||
nr = 1;
|
||||
if (nr * CD_FRAMESIZE_RAW > (q->max_sectors << 9))
|
||||
nr = (q->max_sectors << 9) / CD_FRAMESIZE_RAW;
|
||||
if (nr * CD_FRAMESIZE_RAW > (queue_max_sectors(q) << 9))
|
||||
nr = (queue_max_sectors(q) << 9) / CD_FRAMESIZE_RAW;
|
||||
|
||||
len = nr * CD_FRAMESIZE_RAW;
|
||||
|
||||
|
|
|
|||
|
|
@ -584,8 +584,8 @@ static void gdrom_readdisk_dma(struct work_struct *work)
|
|||
list_for_each_safe(elem, next, &gdrom_deferred) {
|
||||
req = list_entry(elem, struct request, queuelist);
|
||||
spin_unlock(&gdrom_lock);
|
||||
block = req->sector/GD_TO_BLK + GD_SESSION_OFFSET;
|
||||
block_cnt = req->nr_sectors/GD_TO_BLK;
|
||||
block = blk_rq_pos(req)/GD_TO_BLK + GD_SESSION_OFFSET;
|
||||
block_cnt = blk_rq_sectors(req)/GD_TO_BLK;
|
||||
ctrl_outl(PHYSADDR(req->buffer), GDROM_DMA_STARTADDR_REG);
|
||||
ctrl_outl(block_cnt * GDROM_HARD_SECTOR, GDROM_DMA_LENGTH_REG);
|
||||
ctrl_outl(1, GDROM_DMA_DIRECTION_REG);
|
||||
|
|
@ -632,39 +632,35 @@ static void gdrom_readdisk_dma(struct work_struct *work)
|
|||
* before handling ending the request */
|
||||
spin_lock(&gdrom_lock);
|
||||
list_del_init(&req->queuelist);
|
||||
__blk_end_request(req, err, blk_rq_bytes(req));
|
||||
__blk_end_request_all(req, err);
|
||||
}
|
||||
spin_unlock(&gdrom_lock);
|
||||
kfree(read_command);
|
||||
}
|
||||
|
||||
static void gdrom_request_handler_dma(struct request *req)
|
||||
{
|
||||
/* dequeue, add to list of deferred work
|
||||
* and then schedule workqueue */
|
||||
blkdev_dequeue_request(req);
|
||||
list_add_tail(&req->queuelist, &gdrom_deferred);
|
||||
schedule_work(&work);
|
||||
}
|
||||
|
||||
static void gdrom_request(struct request_queue *rq)
|
||||
{
|
||||
struct request *req;
|
||||
|
||||
while ((req = elv_next_request(rq)) != NULL) {
|
||||
while ((req = blk_fetch_request(rq)) != NULL) {
|
||||
if (!blk_fs_request(req)) {
|
||||
printk(KERN_DEBUG "GDROM: Non-fs request ignored\n");
|
||||
end_request(req, 0);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
continue;
|
||||
}
|
||||
if (rq_data_dir(req) != READ) {
|
||||
printk(KERN_NOTICE "GDROM: Read only device -");
|
||||
printk(" write request ignored\n");
|
||||
end_request(req, 0);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
continue;
|
||||
}
|
||||
if (req->nr_sectors)
|
||||
gdrom_request_handler_dma(req);
|
||||
else
|
||||
end_request(req, 0);
|
||||
|
||||
/*
|
||||
* Add to list of deferred work and then schedule
|
||||
* workqueue.
|
||||
*/
|
||||
list_add_tail(&req->queuelist, &gdrom_deferred);
|
||||
schedule_work(&work);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -743,7 +739,7 @@ static void __devinit probe_gdrom_setupdisk(void)
|
|||
|
||||
static int __devinit probe_gdrom_setupqueue(void)
|
||||
{
|
||||
blk_queue_hardsect_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
|
||||
blk_queue_logical_block_size(gd.gdrom_rq, GDROM_HARD_SECTOR);
|
||||
/* using DMA so memory will need to be contiguous */
|
||||
blk_queue_max_hw_segments(gd.gdrom_rq, 1);
|
||||
/* set a large max size to get most from DMA */
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ static int send_request(struct request *req)
|
|||
viopath_targetinst(viopath_hostLp),
|
||||
(u64)req, VIOVERSION << 16,
|
||||
((u64)DEVICE_NR(diskinfo) << 48) | dmaaddr,
|
||||
(u64)req->sector * 512, len, 0);
|
||||
(u64)blk_rq_pos(req) * 512, len, 0);
|
||||
if (hvrc != HvLpEvent_Rc_Good) {
|
||||
printk(VIOCD_KERN_WARNING "hv error on op %d\n", (int)hvrc);
|
||||
return -1;
|
||||
|
|
@ -291,36 +291,19 @@ static int send_request(struct request *req)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void viocd_end_request(struct request *req, int error)
|
||||
{
|
||||
int nsectors = req->hard_nr_sectors;
|
||||
|
||||
/*
|
||||
* Make sure it's fully ended, and ensure that we process
|
||||
* at least one sector.
|
||||
*/
|
||||
if (blk_pc_request(req))
|
||||
nsectors = (req->data_len + 511) >> 9;
|
||||
if (!nsectors)
|
||||
nsectors = 1;
|
||||
|
||||
if (__blk_end_request(req, error, nsectors << 9))
|
||||
BUG();
|
||||
}
|
||||
|
||||
static int rwreq;
|
||||
|
||||
static void do_viocd_request(struct request_queue *q)
|
||||
{
|
||||
struct request *req;
|
||||
|
||||
while ((rwreq == 0) && ((req = elv_next_request(q)) != NULL)) {
|
||||
while ((rwreq == 0) && ((req = blk_fetch_request(q)) != NULL)) {
|
||||
if (!blk_fs_request(req))
|
||||
viocd_end_request(req, -EIO);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
else if (send_request(req) < 0) {
|
||||
printk(VIOCD_KERN_WARNING
|
||||
"unable to send message to OS/400!");
|
||||
viocd_end_request(req, -EIO);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
} else
|
||||
rwreq++;
|
||||
}
|
||||
|
|
@ -486,8 +469,8 @@ static void vio_handle_cd_event(struct HvLpEvent *event)
|
|||
case viocdopen:
|
||||
if (event->xRc == 0) {
|
||||
di = &viocd_diskinfo[bevent->disk];
|
||||
blk_queue_hardsect_size(di->viocd_disk->queue,
|
||||
bevent->block_size);
|
||||
blk_queue_logical_block_size(di->viocd_disk->queue,
|
||||
bevent->block_size);
|
||||
set_capacity(di->viocd_disk,
|
||||
bevent->media_size *
|
||||
bevent->block_size / 512);
|
||||
|
|
@ -531,9 +514,9 @@ return_complete:
|
|||
"with rc %d:0x%04X: %s\n",
|
||||
req, event->xRc,
|
||||
bevent->sub_result, err->msg);
|
||||
viocd_end_request(req, -EIO);
|
||||
__blk_end_request_all(req, -EIO);
|
||||
} else
|
||||
viocd_end_request(req, 0);
|
||||
__blk_end_request_all(req, 0);
|
||||
|
||||
/* restart handling of incoming requests */
|
||||
spin_unlock_irqrestore(&viocd_reqlock, flags);
|
||||
|
|
@ -587,7 +570,7 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
|
|||
struct device_node *node = vdev->dev.archdata.of_node;
|
||||
|
||||
deviceno = vdev->unit_address;
|
||||
if (deviceno > VIOCD_MAX_CD)
|
||||
if (deviceno >= VIOCD_MAX_CD)
|
||||
return -ENODEV;
|
||||
if (!node)
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -97,6 +97,19 @@ config DEVKMEM
|
|||
kind of kernel debugging operations.
|
||||
When in doubt, say "N".
|
||||
|
||||
config BFIN_JTAG_COMM
|
||||
tristate "Blackfin JTAG Communication"
|
||||
depends on BLACKFIN
|
||||
help
|
||||
Add support for emulating a TTY device over the Blackfin JTAG.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called bfin_jtag_comm.
|
||||
|
||||
config BFIN_JTAG_COMM_CONSOLE
|
||||
bool "Console on Blackfin JTAG"
|
||||
depends on BFIN_JTAG_COMM=y
|
||||
|
||||
config SERIAL_NONSTANDARD
|
||||
bool "Non-standard serial port support"
|
||||
depends on HAS_IOMEM
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_LEGACY_PTYS) += pty.o
|
|||
obj-$(CONFIG_UNIX98_PTYS) += pty.o
|
||||
obj-y += misc.o
|
||||
obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o selection.o keyboard.o
|
||||
obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o
|
||||
obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o
|
||||
obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o
|
||||
obj-$(CONFIG_AUDIT) += tty_audit.o
|
||||
|
|
|
|||
365
drivers/char/bfin_jtag_comm.c
Normal file
365
drivers/char/bfin_jtag_comm.c
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
/*
|
||||
* TTY over Blackfin JTAG Communication
|
||||
*
|
||||
* Copyright 2008-2009 Analog Devices Inc.
|
||||
*
|
||||
* Enter bugs at http://blackfin.uclinux.org/
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/circ_buf.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
/* See the Debug/Emulation chapter in the HRM */
|
||||
#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */
|
||||
#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */
|
||||
#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */
|
||||
#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */
|
||||
|
||||
#define DRV_NAME "bfin-jtag-comm"
|
||||
#define DEV_NAME "ttyBFJC"
|
||||
|
||||
#define pr_init(fmt, args...) ({ static const __initdata char __fmt[] = fmt; printk(__fmt, ## args); })
|
||||
#define debug(fmt, args...) pr_debug(DRV_NAME ": " fmt, ## args)
|
||||
|
||||
static inline uint32_t bfin_write_emudat(uint32_t emudat)
|
||||
{
|
||||
__asm__ __volatile__("emudat = %0;" : : "d"(emudat));
|
||||
return emudat;
|
||||
}
|
||||
|
||||
static inline uint32_t bfin_read_emudat(void)
|
||||
{
|
||||
uint32_t emudat;
|
||||
__asm__ __volatile__("%0 = emudat;" : "=d"(emudat));
|
||||
return emudat;
|
||||
}
|
||||
|
||||
static inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d)
|
||||
{
|
||||
return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24));
|
||||
}
|
||||
|
||||
#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */
|
||||
#define CIRC_MASK (CIRC_SIZE - 1)
|
||||
#define circ_empty(circ) ((circ)->head == (circ)->tail)
|
||||
#define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE)
|
||||
#define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE)
|
||||
#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK])
|
||||
|
||||
static struct tty_driver *bfin_jc_driver;
|
||||
static struct task_struct *bfin_jc_kthread;
|
||||
static struct tty_struct * volatile bfin_jc_tty;
|
||||
static unsigned long bfin_jc_count;
|
||||
static DEFINE_MUTEX(bfin_jc_tty_mutex);
|
||||
static volatile struct circ_buf bfin_jc_write_buf;
|
||||
|
||||
static int
|
||||
bfin_jc_emudat_manager(void *arg)
|
||||
{
|
||||
uint32_t inbound_len = 0, outbound_len = 0;
|
||||
|
||||
while (!kthread_should_stop()) {
|
||||
/* no one left to give data to, so sleep */
|
||||
if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) {
|
||||
debug("waiting for readers\n");
|
||||
__set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
schedule();
|
||||
__set_current_state(TASK_RUNNING);
|
||||
}
|
||||
|
||||
/* no data available, so just chill */
|
||||
if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) {
|
||||
debug("waiting for data (in_len = %i) (circ: %i %i)\n",
|
||||
inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head);
|
||||
if (inbound_len)
|
||||
schedule();
|
||||
else
|
||||
schedule_timeout_interruptible(HZ);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if incoming data is ready, eat it */
|
||||
if (bfin_read_DBGSTAT() & EMUDIF) {
|
||||
struct tty_struct *tty;
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
tty = (struct tty_struct *)bfin_jc_tty;
|
||||
if (tty != NULL) {
|
||||
uint32_t emudat = bfin_read_emudat();
|
||||
if (inbound_len == 0) {
|
||||
debug("incoming length: 0x%08x\n", emudat);
|
||||
inbound_len = emudat;
|
||||
} else {
|
||||
size_t num_chars = (4 <= inbound_len ? 4 : inbound_len);
|
||||
debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars);
|
||||
inbound_len -= num_chars;
|
||||
tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars);
|
||||
tty_flip_buffer_push(tty);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
}
|
||||
|
||||
/* if outgoing data is ready, post it */
|
||||
if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) {
|
||||
if (outbound_len == 0) {
|
||||
outbound_len = circ_cnt(&bfin_jc_write_buf);
|
||||
bfin_write_emudat(outbound_len);
|
||||
debug("outgoing length: 0x%08x\n", outbound_len);
|
||||
} else {
|
||||
struct tty_struct *tty;
|
||||
int tail = bfin_jc_write_buf.tail;
|
||||
size_t ate = (4 <= outbound_len ? 4 : outbound_len);
|
||||
uint32_t emudat =
|
||||
bfin_write_emudat_chars(
|
||||
circ_byte(&bfin_jc_write_buf, tail + 0),
|
||||
circ_byte(&bfin_jc_write_buf, tail + 1),
|
||||
circ_byte(&bfin_jc_write_buf, tail + 2),
|
||||
circ_byte(&bfin_jc_write_buf, tail + 3)
|
||||
);
|
||||
bfin_jc_write_buf.tail += ate;
|
||||
outbound_len -= ate;
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
tty = (struct tty_struct *)bfin_jc_tty;
|
||||
if (tty)
|
||||
tty_wakeup(tty);
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
bfin_jc_open(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
debug("open %lu\n", bfin_jc_count);
|
||||
++bfin_jc_count;
|
||||
bfin_jc_tty = tty;
|
||||
wake_up_process(bfin_jc_kthread);
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
bfin_jc_close(struct tty_struct *tty, struct file *filp)
|
||||
{
|
||||
mutex_lock(&bfin_jc_tty_mutex);
|
||||
debug("close %lu\n", bfin_jc_count);
|
||||
if (--bfin_jc_count == 0)
|
||||
bfin_jc_tty = NULL;
|
||||
wake_up_process(bfin_jc_kthread);
|
||||
mutex_unlock(&bfin_jc_tty_mutex);
|
||||
}
|
||||
|
||||
/* XXX: we dont handle the put_char() case where we must handle count = 1 */
|
||||
static int
|
||||
bfin_jc_circ_write(const unsigned char *buf, int count)
|
||||
{
|
||||
int i;
|
||||
count = min(count, circ_free(&bfin_jc_write_buf));
|
||||
debug("going to write chunk of %i bytes\n", count);
|
||||
for (i = 0; i < count; ++i)
|
||||
circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i];
|
||||
bfin_jc_write_buf.head += i;
|
||||
return i;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE
|
||||
# define acquire_console_sem()
|
||||
# define release_console_sem()
|
||||
#endif
|
||||
static int
|
||||
bfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count)
|
||||
{
|
||||
int i;
|
||||
acquire_console_sem();
|
||||
i = bfin_jc_circ_write(buf, count);
|
||||
release_console_sem();
|
||||
wake_up_process(bfin_jc_kthread);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void
|
||||
bfin_jc_flush_chars(struct tty_struct *tty)
|
||||
{
|
||||
wake_up_process(bfin_jc_kthread);
|
||||
}
|
||||
|
||||
static int
|
||||
bfin_jc_write_room(struct tty_struct *tty)
|
||||
{
|
||||
return circ_free(&bfin_jc_write_buf);
|
||||
}
|
||||
|
||||
static int
|
||||
bfin_jc_chars_in_buffer(struct tty_struct *tty)
|
||||
{
|
||||
return circ_cnt(&bfin_jc_write_buf);
|
||||
}
|
||||
|
||||
static void
|
||||
bfin_jc_wait_until_sent(struct tty_struct *tty, int timeout)
|
||||
{
|
||||
unsigned long expire = jiffies + timeout;
|
||||
while (!circ_empty(&bfin_jc_write_buf)) {
|
||||
if (signal_pending(current))
|
||||
break;
|
||||
if (time_after(jiffies, expire))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct tty_operations bfin_jc_ops = {
|
||||
.open = bfin_jc_open,
|
||||
.close = bfin_jc_close,
|
||||
.write = bfin_jc_write,
|
||||
/*.put_char = bfin_jc_put_char,*/
|
||||
.flush_chars = bfin_jc_flush_chars,
|
||||
.write_room = bfin_jc_write_room,
|
||||
.chars_in_buffer = bfin_jc_chars_in_buffer,
|
||||
.wait_until_sent = bfin_jc_wait_until_sent,
|
||||
};
|
||||
|
||||
static int __init bfin_jc_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME);
|
||||
if (IS_ERR(bfin_jc_kthread))
|
||||
return PTR_ERR(bfin_jc_kthread);
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0;
|
||||
bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL);
|
||||
if (!bfin_jc_write_buf.buf)
|
||||
goto err;
|
||||
|
||||
bfin_jc_driver = alloc_tty_driver(1);
|
||||
if (!bfin_jc_driver)
|
||||
goto err;
|
||||
|
||||
bfin_jc_driver->owner = THIS_MODULE;
|
||||
bfin_jc_driver->driver_name = DRV_NAME;
|
||||
bfin_jc_driver->name = DEV_NAME;
|
||||
bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
||||
bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL;
|
||||
bfin_jc_driver->init_termios = tty_std_termios;
|
||||
tty_set_operations(bfin_jc_driver, &bfin_jc_ops);
|
||||
|
||||
ret = tty_register_driver(bfin_jc_driver);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
pr_init(KERN_INFO DRV_NAME ": initialized\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
put_tty_driver(bfin_jc_driver);
|
||||
kfree(bfin_jc_write_buf.buf);
|
||||
kthread_stop(bfin_jc_kthread);
|
||||
return ret;
|
||||
}
|
||||
module_init(bfin_jc_init);
|
||||
|
||||
static void __exit bfin_jc_exit(void)
|
||||
{
|
||||
kthread_stop(bfin_jc_kthread);
|
||||
kfree(bfin_jc_write_buf.buf);
|
||||
tty_unregister_driver(bfin_jc_driver);
|
||||
put_tty_driver(bfin_jc_driver);
|
||||
}
|
||||
module_exit(bfin_jc_exit);
|
||||
|
||||
#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK)
|
||||
static void
|
||||
bfin_jc_straight_buffer_write(const char *buf, unsigned count)
|
||||
{
|
||||
unsigned ate = 0;
|
||||
while (bfin_read_DBGSTAT() & EMUDOF)
|
||||
continue;
|
||||
bfin_write_emudat(count);
|
||||
while (ate < count) {
|
||||
while (bfin_read_DBGSTAT() & EMUDOF)
|
||||
continue;
|
||||
bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]);
|
||||
ate += 4;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE
|
||||
static void
|
||||
bfin_jc_console_write(struct console *co, const char *buf, unsigned count)
|
||||
{
|
||||
if (bfin_jc_kthread == NULL)
|
||||
bfin_jc_straight_buffer_write(buf, count);
|
||||
else
|
||||
bfin_jc_circ_write(buf, count);
|
||||
}
|
||||
|
||||
static struct tty_driver *
|
||||
bfin_jc_console_device(struct console *co, int *index)
|
||||
{
|
||||
*index = co->index;
|
||||
return bfin_jc_driver;
|
||||
}
|
||||
|
||||
static struct console bfin_jc_console = {
|
||||
.name = DEV_NAME,
|
||||
.write = bfin_jc_console_write,
|
||||
.device = bfin_jc_console_device,
|
||||
.flags = CON_ANYTIME | CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
static int __init bfin_jc_console_init(void)
|
||||
{
|
||||
register_console(&bfin_jc_console);
|
||||
return 0;
|
||||
}
|
||||
console_initcall(bfin_jc_console_init);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_EARLY_PRINTK
|
||||
static void __init
|
||||
bfin_jc_early_write(struct console *co, const char *buf, unsigned int count)
|
||||
{
|
||||
bfin_jc_straight_buffer_write(buf, count);
|
||||
}
|
||||
|
||||
static struct __initdata console bfin_jc_early_console = {
|
||||
.name = "early_BFJC",
|
||||
.write = bfin_jc_early_write,
|
||||
.flags = CON_ANYTIME | CON_PRINTBUFFER,
|
||||
.index = -1,
|
||||
};
|
||||
|
||||
struct console * __init
|
||||
bfin_jc_early_init(unsigned int port, unsigned int cflag)
|
||||
{
|
||||
return &bfin_jc_early_console;
|
||||
}
|
||||
#endif
|
||||
|
||||
MODULE_AUTHOR("Mike Frysinger <[email protected]>");
|
||||
MODULE_DESCRIPTION("TTY over Blackfin JTAG Communication");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
@ -604,7 +604,6 @@
|
|||
|
||||
#define NR_PORTS 256
|
||||
|
||||
#define ZE_V1_NPORTS 64
|
||||
#define ZO_V1 0
|
||||
#define ZO_V2 1
|
||||
#define ZE_V1 2
|
||||
|
|
@ -663,18 +662,6 @@
|
|||
static void cy_throttle(struct tty_struct *tty);
|
||||
static void cy_send_xchar(struct tty_struct *tty, char ch);
|
||||
|
||||
#define IS_CYC_Z(card) ((card).num_chips == (unsigned int)-1)
|
||||
|
||||
#define Z_FPGA_CHECK(card) \
|
||||
((readl(&((struct RUNTIME_9060 __iomem *) \
|
||||
((card).ctl_addr))->init_ctrl) & (1<<17)) != 0)
|
||||
|
||||
#define ISZLOADED(card) (((ZO_V1 == readl(&((struct RUNTIME_9060 __iomem *) \
|
||||
((card).ctl_addr))->mail_box_0)) || \
|
||||
Z_FPGA_CHECK(card)) && \
|
||||
(ZFIRM_ID == readl(&((struct FIRM_ID __iomem *) \
|
||||
((card).base_addr+ID_ADDRESS))->signature)))
|
||||
|
||||
#ifndef SERIAL_XMIT_SIZE
|
||||
#define SERIAL_XMIT_SIZE (min(PAGE_SIZE, 4096))
|
||||
#endif
|
||||
|
|
@ -687,8 +674,6 @@ static void cy_send_xchar(struct tty_struct *tty, char ch);
|
|||
#define DRIVER_VERSION 0x02010203
|
||||
#define RAM_SIZE 0x80000
|
||||
|
||||
#define Z_FPGA_LOADED(X) ((readl(&(X)->init_ctrl) & (1<<17)) != 0)
|
||||
|
||||
enum zblock_type {
|
||||
ZBLOCK_PRG = 0,
|
||||
ZBLOCK_FPGA = 1
|
||||
|
|
@ -883,6 +868,29 @@ static void cyz_rx_restart(unsigned long);
|
|||
static struct timer_list cyz_rx_full_timer[NR_PORTS];
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
|
||||
static inline bool cy_is_Z(struct cyclades_card *card)
|
||||
{
|
||||
return card->num_chips == (unsigned int)-1;
|
||||
}
|
||||
|
||||
static inline bool __cyz_fpga_loaded(struct RUNTIME_9060 __iomem *ctl_addr)
|
||||
{
|
||||
return readl(&ctl_addr->init_ctrl) & (1 << 17);
|
||||
}
|
||||
|
||||
static inline bool cyz_fpga_loaded(struct cyclades_card *card)
|
||||
{
|
||||
return __cyz_fpga_loaded(card->ctl_addr.p9060);
|
||||
}
|
||||
|
||||
static inline bool cyz_is_loaded(struct cyclades_card *card)
|
||||
{
|
||||
struct FIRM_ID __iomem *fw_id = card->base_addr + ID_ADDRESS;
|
||||
|
||||
return (card->hw_ver == ZO_V1 || cyz_fpga_loaded(card)) &&
|
||||
readl(&fw_id->signature) == ZFIRM_ID;
|
||||
}
|
||||
|
||||
static inline int serial_paranoia_check(struct cyclades_port *info,
|
||||
char *name, const char *routine)
|
||||
{
|
||||
|
|
@ -1395,19 +1403,15 @@ cyz_fetch_msg(struct cyclades_card *cinfo,
|
|||
unsigned long loc_doorbell;
|
||||
|
||||
firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*cinfo))
|
||||
return -1;
|
||||
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
||||
loc_doorbell = readl(&((struct RUNTIME_9060 __iomem *)
|
||||
(cinfo->ctl_addr))->loc_doorbell);
|
||||
loc_doorbell = readl(&cinfo->ctl_addr.p9060->loc_doorbell);
|
||||
if (loc_doorbell) {
|
||||
*cmd = (char)(0xff & loc_doorbell);
|
||||
*channel = readl(&board_ctrl->fwcmd_channel);
|
||||
*param = (__u32) readl(&board_ctrl->fwcmd_param);
|
||||
cy_writel(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
|
||||
loc_doorbell, 0xffffffff);
|
||||
cy_writel(&cinfo->ctl_addr.p9060->loc_doorbell, 0xffffffff);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1424,15 +1428,14 @@ cyz_issue_cmd(struct cyclades_card *cinfo,
|
|||
unsigned int index;
|
||||
|
||||
firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*cinfo))
|
||||
if (!cyz_is_loaded(cinfo))
|
||||
return -1;
|
||||
|
||||
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
||||
index = 0;
|
||||
pci_doorbell =
|
||||
&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->pci_doorbell;
|
||||
pci_doorbell = &cinfo->ctl_addr.p9060->pci_doorbell;
|
||||
while ((readl(pci_doorbell) & 0xff) != 0) {
|
||||
if (index++ == 1000)
|
||||
return (int)(readl(pci_doorbell) & 0xff);
|
||||
|
|
@ -1624,10 +1627,8 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
|||
static struct BOARD_CTRL __iomem *board_ctrl;
|
||||
static struct CH_CTRL __iomem *ch_ctrl;
|
||||
static struct BUF_CTRL __iomem *buf_ctrl;
|
||||
__u32 channel;
|
||||
__u32 channel, param, fw_ver;
|
||||
__u8 cmd;
|
||||
__u32 param;
|
||||
__u32 hw_ver, fw_ver;
|
||||
int special_count;
|
||||
int delta_count;
|
||||
|
||||
|
|
@ -1635,8 +1636,6 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo)
|
|||
zfw_ctrl = cinfo->base_addr + (readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
fw_ver = readl(&board_ctrl->fw_version);
|
||||
hw_ver = readl(&((struct RUNTIME_9060 __iomem *)(cinfo->ctl_addr))->
|
||||
mail_box_0);
|
||||
|
||||
while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) {
|
||||
special_count = 0;
|
||||
|
|
@ -1737,15 +1736,7 @@ static irqreturn_t cyz_interrupt(int irq, void *dev_id)
|
|||
{
|
||||
struct cyclades_card *cinfo = dev_id;
|
||||
|
||||
if (unlikely(cinfo == NULL)) {
|
||||
#ifdef CY_DEBUG_INTERRUPTS
|
||||
printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",
|
||||
irq);
|
||||
#endif
|
||||
return IRQ_NONE; /* spurious interrupt */
|
||||
}
|
||||
|
||||
if (unlikely(!ISZLOADED(*cinfo))) {
|
||||
if (unlikely(!cyz_is_loaded(cinfo))) {
|
||||
#ifdef CY_DEBUG_INTERRUPTS
|
||||
printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "
|
||||
"(IRQ%d).\n", irq);
|
||||
|
|
@ -1785,7 +1776,6 @@ static void cyz_poll(unsigned long arg)
|
|||
struct tty_struct *tty;
|
||||
struct FIRM_ID __iomem *firm_id;
|
||||
struct ZFW_CTRL __iomem *zfw_ctrl;
|
||||
struct BOARD_CTRL __iomem *board_ctrl;
|
||||
struct BUF_CTRL __iomem *buf_ctrl;
|
||||
unsigned long expires = jiffies + HZ;
|
||||
unsigned int port, card;
|
||||
|
|
@ -1793,19 +1783,17 @@ static void cyz_poll(unsigned long arg)
|
|||
for (card = 0; card < NR_CARDS; card++) {
|
||||
cinfo = &cy_card[card];
|
||||
|
||||
if (!IS_CYC_Z(*cinfo))
|
||||
if (!cy_is_Z(cinfo))
|
||||
continue;
|
||||
if (!ISZLOADED(*cinfo))
|
||||
if (!cyz_is_loaded(cinfo))
|
||||
continue;
|
||||
|
||||
firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
zfw_ctrl = cinfo->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &(zfw_ctrl->board_ctrl);
|
||||
|
||||
/* Skip first polling cycle to avoid racing conditions with the FW */
|
||||
if (!cinfo->intr_enabled) {
|
||||
cinfo->nports = (int)readl(&board_ctrl->n_channel);
|
||||
cinfo->intr_enabled = 1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -1874,7 +1862,7 @@ static int startup(struct cyclades_port *info)
|
|||
|
||||
set_line_char(info);
|
||||
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -1931,7 +1919,7 @@ static int startup(struct cyclades_port *info)
|
|||
base_addr = card->base_addr;
|
||||
|
||||
firm_id = base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*card))
|
||||
if (!cyz_is_loaded(card))
|
||||
return -ENODEV;
|
||||
|
||||
zfw_ctrl = card->base_addr +
|
||||
|
|
@ -2026,7 +2014,7 @@ static void start_xmit(struct cyclades_port *info)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -2070,7 +2058,7 @@ static void shutdown(struct cyclades_port *info)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -2126,7 +2114,7 @@ static void shutdown(struct cyclades_port *info)
|
|||
#endif
|
||||
|
||||
firm_id = base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*card))
|
||||
if (!cyz_is_loaded(card))
|
||||
return;
|
||||
|
||||
zfw_ctrl = card->base_addr +
|
||||
|
|
@ -2233,7 +2221,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
#endif
|
||||
info->port.blocked_open++;
|
||||
|
||||
if (!IS_CYC_Z(*cinfo)) {
|
||||
if (!cy_is_Z(cinfo)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = cinfo->bus_index;
|
||||
|
|
@ -2296,7 +2284,7 @@ block_til_ready(struct tty_struct *tty, struct file *filp,
|
|||
|
||||
base_addr = cinfo->base_addr;
|
||||
firm_id = base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*cinfo)) {
|
||||
if (!cyz_is_loaded(cinfo)) {
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&info->port.open_wait, &wait);
|
||||
return -EINVAL;
|
||||
|
|
@ -2397,16 +2385,14 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
treat it as absent from the system. This
|
||||
will make the user pay attention.
|
||||
*/
|
||||
if (IS_CYC_Z(*info->card)) {
|
||||
if (cy_is_Z(info->card)) {
|
||||
struct cyclades_card *cinfo = info->card;
|
||||
struct FIRM_ID __iomem *firm_id = cinfo->base_addr + ID_ADDRESS;
|
||||
|
||||
if (!ISZLOADED(*cinfo)) {
|
||||
if (((ZE_V1 == readl(&((struct RUNTIME_9060 __iomem *)
|
||||
(cinfo->ctl_addr))->mail_box_0)) &&
|
||||
Z_FPGA_CHECK(*cinfo)) &&
|
||||
(ZFIRM_HLT == readl(
|
||||
&firm_id->signature))) {
|
||||
if (!cyz_is_loaded(cinfo)) {
|
||||
if (cinfo->hw_ver == ZE_V1 && cyz_fpga_loaded(cinfo) &&
|
||||
readl(&firm_id->signature) ==
|
||||
ZFIRM_HLT) {
|
||||
printk(KERN_ERR "cyc:Cyclades-Z Error: you "
|
||||
"need an external power supply for "
|
||||
"this number of ports.\nFirmware "
|
||||
|
|
@ -2423,18 +2409,13 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
interrupts should be enabled as soon as the first open
|
||||
happens to one of its ports. */
|
||||
if (!cinfo->intr_enabled) {
|
||||
struct ZFW_CTRL __iomem *zfw_ctrl;
|
||||
struct BOARD_CTRL __iomem *board_ctrl;
|
||||
|
||||
zfw_ctrl = cinfo->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) &
|
||||
0xfffff);
|
||||
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
u16 intr;
|
||||
|
||||
/* Enable interrupts on the PLX chip */
|
||||
cy_writew(cinfo->ctl_addr + 0x68,
|
||||
readw(cinfo->ctl_addr + 0x68) | 0x0900);
|
||||
intr = readw(&cinfo->ctl_addr.p9060->
|
||||
intr_ctrl_stat) | 0x0900;
|
||||
cy_writew(&cinfo->ctl_addr.p9060->
|
||||
intr_ctrl_stat, intr);
|
||||
/* Enable interrupts on the FW */
|
||||
retval = cyz_issue_cmd(cinfo, 0,
|
||||
C_CM_IRQ_ENBL, 0L);
|
||||
|
|
@ -2442,8 +2423,6 @@ static int cy_open(struct tty_struct *tty, struct file *filp)
|
|||
printk(KERN_ERR "cyc:IRQ enable retval "
|
||||
"was %x\n", retval);
|
||||
}
|
||||
cinfo->nports =
|
||||
(int)readl(&board_ctrl->n_channel);
|
||||
cinfo->intr_enabled = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -2556,7 +2535,7 @@ static void cy_wait_until_sent(struct tty_struct *tty, int timeout)
|
|||
#endif
|
||||
card = info->card;
|
||||
channel = (info->line) - (card->first_line);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -2601,7 +2580,7 @@ static void cy_flush_buffer(struct tty_struct *tty)
|
|||
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
|
||||
spin_unlock_irqrestore(&card->card_lock, flags);
|
||||
|
||||
if (IS_CYC_Z(*card)) { /* If it is a Z card, flush the on-board
|
||||
if (cy_is_Z(card)) { /* If it is a Z card, flush the on-board
|
||||
buffers as well */
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_TX, 0L);
|
||||
|
|
@ -2682,7 +2661,7 @@ static void cy_close(struct tty_struct *tty, struct file *filp)
|
|||
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
int channel = info->line - card->first_line;
|
||||
int index = card->bus_index;
|
||||
void __iomem *base_addr = card->base_addr +
|
||||
|
|
@ -2902,7 +2881,7 @@ static int cy_chars_in_buffer(struct tty_struct *tty)
|
|||
channel = (info->line) - (card->first_line);
|
||||
|
||||
#ifdef Z_EXT_CHARS_IN_BUFFER
|
||||
if (!IS_CYC_Z(cy_card[card])) {
|
||||
if (!cy_is_Z(card)) {
|
||||
#endif /* Z_EXT_CHARS_IN_BUFFER */
|
||||
#ifdef CY_DEBUG_IO
|
||||
printk(KERN_DEBUG "cyc:cy_chars_in_buffer ttyC%d %d\n",
|
||||
|
|
@ -2984,7 +2963,6 @@ static void set_line_char(struct cyclades_port *info)
|
|||
void __iomem *base_addr;
|
||||
int chip, channel, index;
|
||||
unsigned cflag, iflag;
|
||||
unsigned short chip_number;
|
||||
int baud, baud_rate = 0;
|
||||
int i;
|
||||
|
||||
|
|
@ -3013,9 +2991,8 @@ static void set_line_char(struct cyclades_port *info)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
chip_number = channel / 4;
|
||||
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
|
||||
index = card->bus_index;
|
||||
|
||||
|
|
@ -3233,21 +3210,17 @@ static void set_line_char(struct cyclades_port *info)
|
|||
} else {
|
||||
struct FIRM_ID __iomem *firm_id;
|
||||
struct ZFW_CTRL __iomem *zfw_ctrl;
|
||||
struct BOARD_CTRL __iomem *board_ctrl;
|
||||
struct CH_CTRL __iomem *ch_ctrl;
|
||||
struct BUF_CTRL __iomem *buf_ctrl;
|
||||
__u32 sw_flow;
|
||||
int retval;
|
||||
|
||||
firm_id = card->base_addr + ID_ADDRESS;
|
||||
if (!ISZLOADED(*card))
|
||||
if (!cyz_is_loaded(card))
|
||||
return;
|
||||
|
||||
zfw_ctrl = card->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);
|
||||
buf_ctrl = &zfw_ctrl->buf_ctrl[channel];
|
||||
|
||||
/* baud rate */
|
||||
baud = tty_get_baud_rate(info->port.tty);
|
||||
|
|
@ -3457,7 +3430,7 @@ static int get_lsr_info(struct cyclades_port *info, unsigned int __user *value)
|
|||
|
||||
card = info->card;
|
||||
channel = (info->line) - (card->first_line);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3497,7 +3470,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3523,7 +3496,7 @@ static int cy_tiocmget(struct tty_struct *tty, struct file *file)
|
|||
} else {
|
||||
base_addr = card->base_addr;
|
||||
firm_id = card->base_addr + ID_ADDRESS;
|
||||
if (ISZLOADED(*card)) {
|
||||
if (cyz_is_loaded(card)) {
|
||||
zfw_ctrl = card->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
|
@ -3566,7 +3539,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
|
|||
|
||||
card = info->card;
|
||||
channel = (info->line) - (card->first_line);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3641,7 +3614,7 @@ cy_tiocmset(struct tty_struct *tty, struct file *file,
|
|||
base_addr = card->base_addr;
|
||||
|
||||
firm_id = card->base_addr + ID_ADDRESS;
|
||||
if (ISZLOADED(*card)) {
|
||||
if (cyz_is_loaded(card)) {
|
||||
zfw_ctrl = card->base_addr +
|
||||
(readl(&firm_id->zfwctrl_addr) & 0xfffff);
|
||||
board_ctrl = &zfw_ctrl->board_ctrl;
|
||||
|
|
@ -3713,7 +3686,7 @@ static int cy_break(struct tty_struct *tty, int break_state)
|
|||
card = info->card;
|
||||
|
||||
spin_lock_irqsave(&card->card_lock, flags);
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
/* Let the transmit ISR take care of this (since it
|
||||
requires stuffing characters into the output stream).
|
||||
*/
|
||||
|
|
@ -3782,7 +3755,7 @@ static int set_threshold(struct cyclades_port *info, unsigned long value)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3810,7 +3783,7 @@ static int get_threshold(struct cyclades_port *info,
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3844,7 +3817,7 @@ static int set_timeout(struct cyclades_port *info, unsigned long value)
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -3867,7 +3840,7 @@ static int get_timeout(struct cyclades_port *info,
|
|||
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -4121,7 +4094,7 @@ static void cy_send_xchar(struct tty_struct *tty, char ch)
|
|||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
|
||||
if (IS_CYC_Z(*card)) {
|
||||
if (cy_is_Z(card)) {
|
||||
if (ch == STOP_CHAR(tty))
|
||||
cyz_issue_cmd(card, channel, C_CM_SENDXOFF, 0L);
|
||||
else if (ch == START_CHAR(tty))
|
||||
|
|
@ -4154,7 +4127,7 @@ static void cy_throttle(struct tty_struct *tty)
|
|||
card = info->card;
|
||||
|
||||
if (I_IXOFF(tty)) {
|
||||
if (!IS_CYC_Z(*card))
|
||||
if (!cy_is_Z(card))
|
||||
cy_send_xchar(tty, STOP_CHAR(tty));
|
||||
else
|
||||
info->throttle = 1;
|
||||
|
|
@ -4162,7 +4135,7 @@ static void cy_throttle(struct tty_struct *tty)
|
|||
|
||||
if (tty->termios->c_cflag & CRTSCTS) {
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -4219,7 +4192,7 @@ static void cy_unthrottle(struct tty_struct *tty)
|
|||
if (tty->termios->c_cflag & CRTSCTS) {
|
||||
card = info->card;
|
||||
channel = info->line - card->first_line;
|
||||
if (!IS_CYC_Z(*card)) {
|
||||
if (!cy_is_Z(card)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
index = card->bus_index;
|
||||
|
|
@ -4263,7 +4236,7 @@ static void cy_stop(struct tty_struct *tty)
|
|||
|
||||
cinfo = info->card;
|
||||
channel = info->line - cinfo->first_line;
|
||||
if (!IS_CYC_Z(*cinfo)) {
|
||||
if (!cy_is_Z(cinfo)) {
|
||||
index = cinfo->bus_index;
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
|
|
@ -4296,7 +4269,7 @@ static void cy_start(struct tty_struct *tty)
|
|||
cinfo = info->card;
|
||||
channel = info->line - cinfo->first_line;
|
||||
index = cinfo->bus_index;
|
||||
if (!IS_CYC_Z(*cinfo)) {
|
||||
if (!cy_is_Z(cinfo)) {
|
||||
chip = channel >> 2;
|
||||
channel &= 0x03;
|
||||
base_addr = cinfo->base_addr + (cy_chip_offset[chip] << index);
|
||||
|
|
@ -4347,33 +4320,20 @@ static void cy_hangup(struct tty_struct *tty)
|
|||
static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
||||
{
|
||||
struct cyclades_port *info;
|
||||
u32 uninitialized_var(mailbox);
|
||||
unsigned int nports, port;
|
||||
unsigned int port;
|
||||
unsigned short chip_number;
|
||||
int uninitialized_var(index);
|
||||
|
||||
spin_lock_init(&cinfo->card_lock);
|
||||
cinfo->intr_enabled = 0;
|
||||
|
||||
if (IS_CYC_Z(*cinfo)) { /* Cyclades-Z */
|
||||
mailbox = readl(&((struct RUNTIME_9060 __iomem *)
|
||||
cinfo->ctl_addr)->mail_box_0);
|
||||
nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8;
|
||||
cinfo->intr_enabled = 0;
|
||||
cinfo->nports = 0; /* Will be correctly set later, after
|
||||
Z FW is loaded */
|
||||
} else {
|
||||
index = cinfo->bus_index;
|
||||
nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips;
|
||||
}
|
||||
|
||||
cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL);
|
||||
cinfo->ports = kcalloc(cinfo->nports, sizeof(*cinfo->ports),
|
||||
GFP_KERNEL);
|
||||
if (cinfo->ports == NULL) {
|
||||
printk(KERN_ERR "Cyclades: cannot allocate ports\n");
|
||||
cinfo->nports = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
for (port = cinfo->first_line; port < cinfo->first_line + nports;
|
||||
for (port = cinfo->first_line; port < cinfo->first_line + cinfo->nports;
|
||||
port++) {
|
||||
info = &cinfo->ports[port - cinfo->first_line];
|
||||
tty_port_init(&info->port);
|
||||
|
|
@ -4387,9 +4347,9 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
|||
init_completion(&info->shutdown_wait);
|
||||
init_waitqueue_head(&info->delta_msr_wait);
|
||||
|
||||
if (IS_CYC_Z(*cinfo)) {
|
||||
if (cy_is_Z(cinfo)) {
|
||||
info->type = PORT_STARTECH;
|
||||
if (mailbox == ZO_V1)
|
||||
if (cinfo->hw_ver == ZO_V1)
|
||||
info->xmit_fifo_size = CYZ_FIFO_SIZE;
|
||||
else
|
||||
info->xmit_fifo_size = 4 * CYZ_FIFO_SIZE;
|
||||
|
|
@ -4398,6 +4358,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
|||
cyz_rx_restart, (unsigned long)info);
|
||||
#endif
|
||||
} else {
|
||||
int index = cinfo->bus_index;
|
||||
info->type = PORT_CIRRUS;
|
||||
info->xmit_fifo_size = CyMAX_CHAR_FIFO;
|
||||
info->cor1 = CyPARITY_NONE | Cy_1_STOP | Cy_8_BITS;
|
||||
|
|
@ -4430,7 +4391,7 @@ static int __devinit cy_init_card(struct cyclades_card *cinfo)
|
|||
}
|
||||
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
if (IS_CYC_Z(*cinfo) && !timer_pending(&cyz_timerlist)) {
|
||||
if (cy_is_Z(cinfo) && !timer_pending(&cyz_timerlist)) {
|
||||
mod_timer(&cyz_timerlist, jiffies + 1);
|
||||
#ifdef CY_PCI_DEBUG
|
||||
printk(KERN_DEBUG "Cyclades-Z polling initialized\n");
|
||||
|
|
@ -4621,11 +4582,12 @@ static int __init cy_detect_isa(void)
|
|||
|
||||
/* set cy_card */
|
||||
cy_card[j].base_addr = cy_isa_address;
|
||||
cy_card[j].ctl_addr = NULL;
|
||||
cy_card[j].ctl_addr.p9050 = NULL;
|
||||
cy_card[j].irq = (int)cy_isa_irq;
|
||||
cy_card[j].bus_index = 0;
|
||||
cy_card[j].first_line = cy_next_channel;
|
||||
cy_card[j].num_chips = cy_isa_nchan / 4;
|
||||
cy_card[j].num_chips = cy_isa_nchan / CyPORTS_PER_CHIP;
|
||||
cy_card[j].nports = cy_isa_nchan;
|
||||
if (cy_init_card(&cy_card[j])) {
|
||||
cy_card[j].base_addr = NULL;
|
||||
free_irq(cy_isa_irq, &cy_card[j]);
|
||||
|
|
@ -4781,7 +4743,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
struct CUSTOM_REG __iomem *cust = base_addr;
|
||||
struct ZFW_CTRL __iomem *pt_zfwctrl;
|
||||
void __iomem *tmp;
|
||||
u32 mailbox, status;
|
||||
u32 mailbox, status, nchan;
|
||||
unsigned int i;
|
||||
int retval;
|
||||
|
||||
|
|
@ -4793,7 +4755,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
|
||||
/* Check whether the firmware is already loaded and running. If
|
||||
positive, skip this board */
|
||||
if (Z_FPGA_LOADED(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
|
||||
if (__cyz_fpga_loaded(ctl_addr) && readl(&fid->signature) == ZFIRM_ID) {
|
||||
u32 cntval = readl(base_addr + 0x190);
|
||||
|
||||
udelay(100);
|
||||
|
|
@ -4812,7 +4774,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
|
||||
mailbox = readl(&ctl_addr->mail_box_0);
|
||||
|
||||
if (mailbox == 0 || Z_FPGA_LOADED(ctl_addr)) {
|
||||
if (mailbox == 0 || __cyz_fpga_loaded(ctl_addr)) {
|
||||
/* stops CPU and set window to beginning of RAM */
|
||||
cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
|
||||
cy_writel(&cust->cpu_stop, 0);
|
||||
|
|
@ -4828,7 +4790,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
base_addr);
|
||||
if (retval)
|
||||
goto err_rel;
|
||||
if (!Z_FPGA_LOADED(ctl_addr)) {
|
||||
if (!__cyz_fpga_loaded(ctl_addr)) {
|
||||
dev_err(&pdev->dev, "fw upload successful, but fw is "
|
||||
"not loaded\n");
|
||||
goto err_rel;
|
||||
|
|
@ -4887,7 +4849,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
"system before loading the new FW to the "
|
||||
"Cyclades-Z.\n");
|
||||
|
||||
if (Z_FPGA_LOADED(ctl_addr))
|
||||
if (__cyz_fpga_loaded(ctl_addr))
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
|
||||
retval = -EIO;
|
||||
|
|
@ -4902,16 +4864,16 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
base_addr + ID_ADDRESS, readl(&fid->zfwctrl_addr),
|
||||
base_addr + readl(&fid->zfwctrl_addr));
|
||||
|
||||
nchan = readl(&pt_zfwctrl->board_ctrl.n_channel);
|
||||
dev_info(&pdev->dev, "Cyclades-Z FW loaded: version = %x, ports = %u\n",
|
||||
readl(&pt_zfwctrl->board_ctrl.fw_version),
|
||||
readl(&pt_zfwctrl->board_ctrl.n_channel));
|
||||
readl(&pt_zfwctrl->board_ctrl.fw_version), nchan);
|
||||
|
||||
if (readl(&pt_zfwctrl->board_ctrl.n_channel) == 0) {
|
||||
if (nchan == 0) {
|
||||
dev_warn(&pdev->dev, "no Cyclades-Z ports were found. Please "
|
||||
"check the connection between the Z host card and the "
|
||||
"serial expanders.\n");
|
||||
|
||||
if (Z_FPGA_LOADED(ctl_addr))
|
||||
if (__cyz_fpga_loaded(ctl_addr))
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
|
||||
dev_info(&pdev->dev, "Null number of ports detected. Board "
|
||||
|
|
@ -4932,9 +4894,7 @@ static int __devinit cyz_load_fw(struct pci_dev *pdev, void __iomem *base_addr,
|
|||
cy_writel(&ctl_addr->intr_ctrl_stat, readl(&ctl_addr->intr_ctrl_stat) |
|
||||
0x00030800UL);
|
||||
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
|
||||
return 0;
|
||||
return nchan;
|
||||
err_rel:
|
||||
release_firmware(fw);
|
||||
err:
|
||||
|
|
@ -4946,7 +4906,7 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
{
|
||||
void __iomem *addr0 = NULL, *addr2 = NULL;
|
||||
char *card_name = NULL;
|
||||
u32 mailbox;
|
||||
u32 uninitialized_var(mailbox);
|
||||
unsigned int device_id, nchan = 0, card_no, i;
|
||||
unsigned char plx_ver;
|
||||
int retval, irq;
|
||||
|
|
@ -5023,11 +4983,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
/* Disable interrupts on the PLX before resetting it */
|
||||
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) & ~0x0900);
|
||||
cy_writew(&ctl_addr->intr_ctrl_stat,
|
||||
readw(&ctl_addr->intr_ctrl_stat) & ~0x0900);
|
||||
|
||||
plx_init(pdev, irq, addr0);
|
||||
|
||||
mailbox = (u32)readl(&ctl_addr->mail_box_0);
|
||||
mailbox = readl(&ctl_addr->mail_box_0);
|
||||
|
||||
addr2 = ioremap_nocache(pci_resource_start(pdev, 2),
|
||||
mailbox == ZE_V1 ? CyPCI_Ze_win : CyPCI_Zwin);
|
||||
|
|
@ -5038,12 +4999,8 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
|
||||
if (mailbox == ZE_V1) {
|
||||
card_name = "Cyclades-Ze";
|
||||
|
||||
readl(&ctl_addr->mail_box_0);
|
||||
nchan = ZE_V1_NPORTS;
|
||||
} else {
|
||||
card_name = "Cyclades-8Zo";
|
||||
|
||||
#ifdef CY_PCI_DEBUG
|
||||
if (mailbox == ZO_V1) {
|
||||
cy_writel(&ctl_addr->loc_addr_base, WIN_CREG);
|
||||
|
|
@ -5065,15 +5022,12 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
*/
|
||||
if ((mailbox == ZO_V1) || (mailbox == ZO_V2))
|
||||
cy_writel(addr2 + ID_ADDRESS, 0L);
|
||||
|
||||
retval = cyz_load_fw(pdev, addr2, addr0, irq);
|
||||
if (retval)
|
||||
goto err_unmap;
|
||||
/* This must be a Cyclades-8Zo/PCI. The extendable
|
||||
version will have a different device_id and will
|
||||
be allocated its maximum number of ports. */
|
||||
nchan = 8;
|
||||
}
|
||||
|
||||
retval = cyz_load_fw(pdev, addr2, addr0, irq);
|
||||
if (retval <= 0)
|
||||
goto err_unmap;
|
||||
nchan = retval;
|
||||
}
|
||||
|
||||
if ((cy_next_channel + nchan) > NR_PORTS) {
|
||||
|
|
@ -5103,8 +5057,10 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
dev_err(&pdev->dev, "could not allocate IRQ\n");
|
||||
goto err_unmap;
|
||||
}
|
||||
cy_card[card_no].num_chips = nchan / 4;
|
||||
cy_card[card_no].num_chips = nchan / CyPORTS_PER_CHIP;
|
||||
} else {
|
||||
cy_card[card_no].hw_ver = mailbox;
|
||||
cy_card[card_no].num_chips = (unsigned int)-1;
|
||||
#ifdef CONFIG_CYZ_INTR
|
||||
/* allocate IRQ only if board has an IRQ */
|
||||
if (irq != 0 && irq != 255) {
|
||||
|
|
@ -5117,15 +5073,15 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
}
|
||||
}
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
cy_card[card_no].num_chips = (unsigned int)-1;
|
||||
}
|
||||
|
||||
/* set cy_card */
|
||||
cy_card[card_no].base_addr = addr2;
|
||||
cy_card[card_no].ctl_addr = addr0;
|
||||
cy_card[card_no].ctl_addr.p9050 = addr0;
|
||||
cy_card[card_no].irq = irq;
|
||||
cy_card[card_no].bus_index = 1;
|
||||
cy_card[card_no].first_line = cy_next_channel;
|
||||
cy_card[card_no].nports = nchan;
|
||||
retval = cy_init_card(&cy_card[card_no]);
|
||||
if (retval)
|
||||
goto err_null;
|
||||
|
|
@ -5138,17 +5094,20 @@ static int __devinit cy_pci_probe(struct pci_dev *pdev,
|
|||
plx_ver = readb(addr2 + CyPLX_VER) & 0x0f;
|
||||
switch (plx_ver) {
|
||||
case PLX_9050:
|
||||
|
||||
cy_writeb(addr0 + 0x4c, 0x43);
|
||||
break;
|
||||
|
||||
case PLX_9060:
|
||||
case PLX_9080:
|
||||
default: /* Old boards, use PLX_9060 */
|
||||
plx_init(pdev, irq, addr0);
|
||||
cy_writew(addr0 + 0x68, readw(addr0 + 0x68) | 0x0900);
|
||||
{
|
||||
struct RUNTIME_9060 __iomem *ctl_addr = addr0;
|
||||
plx_init(pdev, irq, ctl_addr);
|
||||
cy_writew(&ctl_addr->intr_ctrl_stat,
|
||||
readw(&ctl_addr->intr_ctrl_stat) | 0x0900);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "%s/PCI #%d found: %d channels starting from "
|
||||
|
|
@ -5179,22 +5138,23 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev)
|
|||
unsigned int i;
|
||||
|
||||
/* non-Z with old PLX */
|
||||
if (!IS_CYC_Z(*cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
|
||||
if (!cy_is_Z(cinfo) && (readb(cinfo->base_addr + CyPLX_VER) & 0x0f) ==
|
||||
PLX_9050)
|
||||
cy_writeb(cinfo->ctl_addr + 0x4c, 0);
|
||||
cy_writeb(cinfo->ctl_addr.p9050 + 0x4c, 0);
|
||||
else
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
if (!IS_CYC_Z(*cinfo))
|
||||
if (!cy_is_Z(cinfo))
|
||||
#endif
|
||||
cy_writew(cinfo->ctl_addr + 0x68,
|
||||
readw(cinfo->ctl_addr + 0x68) & ~0x0900);
|
||||
cy_writew(&cinfo->ctl_addr.p9060->intr_ctrl_stat,
|
||||
readw(&cinfo->ctl_addr.p9060->intr_ctrl_stat) &
|
||||
~0x0900);
|
||||
|
||||
iounmap(cinfo->base_addr);
|
||||
if (cinfo->ctl_addr)
|
||||
iounmap(cinfo->ctl_addr);
|
||||
if (cinfo->ctl_addr.p9050)
|
||||
iounmap(cinfo->ctl_addr.p9050);
|
||||
if (cinfo->irq
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
&& !IS_CYC_Z(*cinfo)
|
||||
&& !cy_is_Z(cinfo)
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
)
|
||||
free_irq(cinfo->irq, cinfo);
|
||||
|
|
@ -5240,7 +5200,7 @@ static int cyclades_proc_show(struct seq_file *m, void *v)
|
|||
(cur_jifs - info->idle_stats.recv_idle)/
|
||||
HZ, info->idle_stats.overruns,
|
||||
/* FIXME: double check locking */
|
||||
(long)info->port.tty->ldisc.ops->num);
|
||||
(long)info->port.tty->ldisc->ops->num);
|
||||
else
|
||||
seq_printf(m, "%3d %8lu %10lu %8lu "
|
||||
"%10lu %8lu %9lu %6ld\n",
|
||||
|
|
@ -5386,11 +5346,11 @@ static void __exit cy_cleanup_module(void)
|
|||
/* clear interrupt */
|
||||
cy_writeb(card->base_addr + Cy_ClrIntr, 0);
|
||||
iounmap(card->base_addr);
|
||||
if (card->ctl_addr)
|
||||
iounmap(card->ctl_addr);
|
||||
if (card->ctl_addr.p9050)
|
||||
iounmap(card->ctl_addr.p9050);
|
||||
if (card->irq
|
||||
#ifndef CONFIG_CYZ_INTR
|
||||
&& !IS_CYC_Z(*card)
|
||||
&& !cy_is_Z(card)
|
||||
#endif /* CONFIG_CYZ_INTR */
|
||||
)
|
||||
free_irq(card->irq, card);
|
||||
|
|
|
|||
|
|
@ -745,7 +745,7 @@ static int epca_carrier_raised(struct tty_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void epca_raise_dtr_rts(struct tty_port *port)
|
||||
static void epca_dtr_rts(struct tty_port *port, int onoff)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -925,7 +925,7 @@ static const struct tty_operations pc_ops = {
|
|||
|
||||
static const struct tty_port_operations epca_port_ops = {
|
||||
.carrier_raised = epca_carrier_raised,
|
||||
.raise_dtr_rts = epca_raise_dtr_rts,
|
||||
.dtr_rts = epca_dtr_rts,
|
||||
};
|
||||
|
||||
static int info_open(struct tty_struct *tty, struct file *filp)
|
||||
|
|
@ -1518,7 +1518,7 @@ static void doevent(int crd)
|
|||
if (event & MODEMCHG_IND) {
|
||||
/* A modem signal change has been indicated */
|
||||
ch->imodem = mstat;
|
||||
if (test_bit(ASYNC_CHECK_CD, &ch->port.flags)) {
|
||||
if (test_bit(ASYNCB_CHECK_CD, &ch->port.flags)) {
|
||||
/* We are now receiving dcd */
|
||||
if (mstat & ch->dcd)
|
||||
wake_up_interruptible(&ch->port.open_wait);
|
||||
|
|
@ -1765,9 +1765,9 @@ static void epcaparam(struct tty_struct *tty, struct channel *ch)
|
|||
* that the driver will wait on carrier detect.
|
||||
*/
|
||||
if (ts->c_cflag & CLOCAL)
|
||||
clear_bit(ASYNC_CHECK_CD, &ch->port.flags);
|
||||
clear_bit(ASYNCB_CHECK_CD, &ch->port.flags);
|
||||
else
|
||||
set_bit(ASYNC_CHECK_CD, &ch->port.flags);
|
||||
set_bit(ASYNCB_CHECK_CD, &ch->port.flags);
|
||||
mval = ch->m_dtr | ch->m_rts;
|
||||
} /* End CBAUD not detected */
|
||||
iflag = termios2digi_i(ch, ts->c_iflag);
|
||||
|
|
@ -2114,8 +2114,8 @@ static int pc_ioctl(struct tty_struct *tty, struct file *file,
|
|||
tty_wait_until_sent(tty, 0);
|
||||
} else {
|
||||
/* ldisc lock already held in ioctl */
|
||||
if (tty->ldisc.ops->flush_buffer)
|
||||
tty->ldisc.ops->flush_buffer(tty);
|
||||
if (tty->ldisc->ops->flush_buffer)
|
||||
tty->ldisc->ops->flush_buffer(tty);
|
||||
}
|
||||
unlock_kernel();
|
||||
/* Fall Thru */
|
||||
|
|
@ -2244,7 +2244,8 @@ static void do_softint(struct work_struct *work)
|
|||
if (test_and_clear_bit(EPCA_EVENT_HANGUP, &ch->event)) {
|
||||
tty_hangup(tty);
|
||||
wake_up_interruptible(&ch->port.open_wait);
|
||||
clear_bit(ASYNC_NORMAL_ACTIVE, &ch->port.flags);
|
||||
clear_bit(ASYNCB_NORMAL_ACTIVE,
|
||||
&ch->port.flags);
|
||||
}
|
||||
}
|
||||
tty_kref_put(tty);
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ static void hpet_timer_set_irq(struct hpet_dev *devp)
|
|||
break;
|
||||
}
|
||||
|
||||
gsi = acpi_register_gsi(irq, ACPI_LEVEL_SENSITIVE,
|
||||
gsi = acpi_register_gsi(NULL, irq, ACPI_LEVEL_SENSITIVE,
|
||||
ACPI_ACTIVE_LOW);
|
||||
if (gsi > 0)
|
||||
break;
|
||||
|
|
@ -939,7 +939,7 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
|
|||
irqp = &res->data.extended_irq;
|
||||
|
||||
for (i = 0; i < irqp->interrupt_count; i++) {
|
||||
irq = acpi_register_gsi(irqp->interrupts[i],
|
||||
irq = acpi_register_gsi(NULL, irqp->interrupts[i],
|
||||
irqp->triggering, irqp->polarity);
|
||||
if (irq < 0)
|
||||
return AE_ERROR;
|
||||
|
|
|
|||
|
|
@ -868,11 +868,11 @@ i2Input(i2ChanStrPtr pCh)
|
|||
amountToMove = count;
|
||||
}
|
||||
// Move the first block
|
||||
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
|
||||
pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
|
||||
&(pCh->Ibuf[stripIndex]), NULL, amountToMove );
|
||||
// If we needed to wrap, do the second data move
|
||||
if (count > amountToMove) {
|
||||
pCh->pTTY->ldisc.ops->receive_buf( pCh->pTTY,
|
||||
pCh->pTTY->ldisc->ops->receive_buf( pCh->pTTY,
|
||||
pCh->Ibuf, NULL, count - amountToMove );
|
||||
}
|
||||
// Bump and wrap the stripIndex all at once by the amount of data read. This
|
||||
|
|
|
|||
|
|
@ -1315,8 +1315,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)
|
|||
if (tty->pgrp)
|
||||
kill_pgrp(tty->pgrp, sig, 1);
|
||||
if (flush || !L_NOFLSH(tty)) {
|
||||
if ( tty->ldisc.ops->flush_buffer )
|
||||
tty->ldisc.ops->flush_buffer(tty);
|
||||
if ( tty->ldisc->ops->flush_buffer )
|
||||
tty->ldisc->ops->flush_buffer(tty);
|
||||
i2InputFlush( tty->driver_data );
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2856,6 +2856,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
|
|||
/* Assume a single IPMB channel at zero. */
|
||||
intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
|
||||
intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
|
||||
intf->curr_channel = IPMI_MAX_CHANNELS;
|
||||
}
|
||||
|
||||
if (rv == 0)
|
||||
|
|
@ -3648,13 +3649,13 @@ static int handle_new_recv_msg(ipmi_smi_t intf,
|
|||
}
|
||||
|
||||
/*
|
||||
** We need to make sure the channels have been initialized.
|
||||
** The channel_handler routine will set the "curr_channel"
|
||||
** equal to or greater than IPMI_MAX_CHANNELS when all the
|
||||
** channels for this interface have been initialized.
|
||||
*/
|
||||
* We need to make sure the channels have been initialized.
|
||||
* The channel_handler routine will set the "curr_channel"
|
||||
* equal to or greater than IPMI_MAX_CHANNELS when all the
|
||||
* channels for this interface have been initialized.
|
||||
*/
|
||||
if (intf->curr_channel < IPMI_MAX_CHANNELS) {
|
||||
requeue = 1; /* Just put the message back for now */
|
||||
requeue = 0; /* Throw the message away */
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,7 +329,7 @@ static inline void drop_rts(struct isi_port *port)
|
|||
|
||||
/* card->lock MUST NOT be held */
|
||||
|
||||
static void isicom_raise_dtr_rts(struct tty_port *port)
|
||||
static void isicom_dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
struct isi_port *ip = container_of(port, struct isi_port, port);
|
||||
struct isi_board *card = ip->card;
|
||||
|
|
@ -339,10 +339,17 @@ static void isicom_raise_dtr_rts(struct tty_port *port)
|
|||
if (!lock_card(card))
|
||||
return;
|
||||
|
||||
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
|
||||
outw(0x0f04, base);
|
||||
InterruptTheCard(base);
|
||||
ip->status |= (ISI_DTR | ISI_RTS);
|
||||
if (on) {
|
||||
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
|
||||
outw(0x0f04, base);
|
||||
InterruptTheCard(base);
|
||||
ip->status |= (ISI_DTR | ISI_RTS);
|
||||
} else {
|
||||
outw(0x8000 | (channel << card->shift_count) | 0x02, base);
|
||||
outw(0x0C04, base);
|
||||
InterruptTheCard(base);
|
||||
ip->status &= ~(ISI_DTR | ISI_RTS);
|
||||
}
|
||||
unlock_card(card);
|
||||
}
|
||||
|
||||
|
|
@ -1339,7 +1346,7 @@ static const struct tty_operations isicom_ops = {
|
|||
|
||||
static const struct tty_port_operations isicom_port_ops = {
|
||||
.carrier_raised = isicom_carrier_raised,
|
||||
.raise_dtr_rts = isicom_raise_dtr_rts,
|
||||
.dtr_rts = isicom_dtr_rts,
|
||||
};
|
||||
|
||||
static int __devinit reset_card(struct pci_dev *pdev,
|
||||
|
|
|
|||
|
|
@ -1140,14 +1140,14 @@ static int stli_carrier_raised(struct tty_port *port)
|
|||
return (portp->sigs & TIOCM_CD) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void stli_raise_dtr_rts(struct tty_port *port)
|
||||
static void stli_dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
struct stliport *portp = container_of(port, struct stliport, port);
|
||||
struct stlibrd *brdp = stli_brds[portp->brdnr];
|
||||
stli_mkasysigs(&portp->asig, 1, 1);
|
||||
stli_mkasysigs(&portp->asig, on, on);
|
||||
if (stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig,
|
||||
sizeof(asysigs_t), 0) < 0)
|
||||
printk(KERN_WARNING "istallion: dtr raise failed.\n");
|
||||
printk(KERN_WARNING "istallion: dtr set failed.\n");
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -4417,7 +4417,7 @@ static const struct tty_operations stli_ops = {
|
|||
|
||||
static const struct tty_port_operations stli_port_ops = {
|
||||
.carrier_raised = stli_carrier_raised,
|
||||
.raise_dtr_rts = stli_raise_dtr_rts,
|
||||
.dtr_rts = stli_dtr_rts,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -694,6 +694,8 @@ static ssize_t read_zero(struct file * file, char __user * buf,
|
|||
written += chunk - unwritten;
|
||||
if (unwritten)
|
||||
break;
|
||||
if (signal_pending(current))
|
||||
return written ? written : -ERESTARTSYS;
|
||||
buf += chunk;
|
||||
count -= chunk;
|
||||
cond_resched();
|
||||
|
|
|
|||
|
|
@ -1184,6 +1184,11 @@ static int moxa_open(struct tty_struct *tty, struct file *filp)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (port % MAX_PORTS_PER_BOARD >= brd->numPorts) {
|
||||
mutex_unlock(&moxa_openlock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ch = &brd->ports[port % MAX_PORTS_PER_BOARD];
|
||||
ch->port.count++;
|
||||
tty->driver_data = ch;
|
||||
|
|
|
|||
|
|
@ -547,14 +547,18 @@ static int mxser_carrier_raised(struct tty_port *port)
|
|||
return (inb(mp->ioaddr + UART_MSR) & UART_MSR_DCD)?1:0;
|
||||
}
|
||||
|
||||
static void mxser_raise_dtr_rts(struct tty_port *port)
|
||||
static void mxser_dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
struct mxser_port *mp = container_of(port, struct mxser_port, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&mp->slock, flags);
|
||||
outb(inb(mp->ioaddr + UART_MCR) |
|
||||
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
|
||||
if (on)
|
||||
outb(inb(mp->ioaddr + UART_MCR) |
|
||||
UART_MCR_DTR | UART_MCR_RTS, mp->ioaddr + UART_MCR);
|
||||
else
|
||||
outb(inb(mp->ioaddr + UART_MCR)&~(UART_MCR_DTR | UART_MCR_RTS),
|
||||
mp->ioaddr + UART_MCR);
|
||||
spin_unlock_irqrestore(&mp->slock, flags);
|
||||
}
|
||||
|
||||
|
|
@ -2356,7 +2360,7 @@ static const struct tty_operations mxser_ops = {
|
|||
|
||||
struct tty_port_operations mxser_port_ops = {
|
||||
.carrier_raised = mxser_carrier_raised,
|
||||
.raise_dtr_rts = mxser_raise_dtr_rts,
|
||||
.dtr_rts = mxser_dtr_rts,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -2711,7 +2715,7 @@ static int __init mxser_module_init(void)
|
|||
continue;
|
||||
|
||||
brd = &mxser_boards[m];
|
||||
retval = mxser_get_ISA_conf(!ioaddr[b], brd);
|
||||
retval = mxser_get_ISA_conf(ioaddr[b], brd);
|
||||
if (retval <= 0) {
|
||||
brd->info = NULL;
|
||||
continue;
|
||||
|
|
|
|||
|
|
@ -342,8 +342,8 @@ static int n_hdlc_tty_open (struct tty_struct *tty)
|
|||
#endif
|
||||
|
||||
/* Flush any pending characters in the driver and discipline. */
|
||||
if (tty->ldisc.ops->flush_buffer)
|
||||
tty->ldisc.ops->flush_buffer(tty);
|
||||
if (tty->ldisc->ops->flush_buffer)
|
||||
tty->ldisc->ops->flush_buffer(tty);
|
||||
|
||||
tty_driver_flush_buffer(tty);
|
||||
|
||||
|
|
|
|||
|
|
@ -73,24 +73,6 @@
|
|||
#define ECHO_OP_SET_CANON_COL 0x81
|
||||
#define ECHO_OP_ERASE_TAB 0x82
|
||||
|
||||
static inline unsigned char *alloc_buf(void)
|
||||
{
|
||||
gfp_t prio = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
|
||||
|
||||
if (PAGE_SIZE != N_TTY_BUF_SIZE)
|
||||
return kmalloc(N_TTY_BUF_SIZE, prio);
|
||||
else
|
||||
return (unsigned char *)__get_free_page(prio);
|
||||
}
|
||||
|
||||
static inline void free_buf(unsigned char *buf)
|
||||
{
|
||||
if (PAGE_SIZE != N_TTY_BUF_SIZE)
|
||||
kfree(buf);
|
||||
else
|
||||
free_page((unsigned long) buf);
|
||||
}
|
||||
|
||||
static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
|
||||
unsigned char __user *ptr)
|
||||
{
|
||||
|
|
@ -1558,11 +1540,11 @@ static void n_tty_close(struct tty_struct *tty)
|
|||
{
|
||||
n_tty_flush_buffer(tty);
|
||||
if (tty->read_buf) {
|
||||
free_buf(tty->read_buf);
|
||||
kfree(tty->read_buf);
|
||||
tty->read_buf = NULL;
|
||||
}
|
||||
if (tty->echo_buf) {
|
||||
free_buf(tty->echo_buf);
|
||||
kfree(tty->echo_buf);
|
||||
tty->echo_buf = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -1584,17 +1566,16 @@ static int n_tty_open(struct tty_struct *tty)
|
|||
|
||||
/* These are ugly. Currently a malloc failure here can panic */
|
||||
if (!tty->read_buf) {
|
||||
tty->read_buf = alloc_buf();
|
||||
tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
|
||||
if (!tty->read_buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (!tty->echo_buf) {
|
||||
tty->echo_buf = alloc_buf();
|
||||
tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
|
||||
|
||||
if (!tty->echo_buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset(tty->read_buf, 0, N_TTY_BUF_SIZE);
|
||||
memset(tty->echo_buf, 0, N_TTY_BUF_SIZE);
|
||||
reset_buffer_flags(tty);
|
||||
tty->column = 0;
|
||||
n_tty_set_termios(tty, NULL);
|
||||
|
|
|
|||
|
|
@ -383,7 +383,7 @@ static void async_mode(MGSLPC_INFO *info);
|
|||
static void tx_timeout(unsigned long context);
|
||||
|
||||
static int carrier_raised(struct tty_port *port);
|
||||
static void raise_dtr_rts(struct tty_port *port);
|
||||
static void dtr_rts(struct tty_port *port, int onoff);
|
||||
|
||||
#if SYNCLINK_GENERIC_HDLC
|
||||
#define dev_to_port(D) (dev_to_hdlc(D)->priv)
|
||||
|
|
@ -513,7 +513,7 @@ static void ldisc_receive_buf(struct tty_struct *tty,
|
|||
|
||||
static const struct tty_port_operations mgslpc_port_ops = {
|
||||
.carrier_raised = carrier_raised,
|
||||
.raise_dtr_rts = raise_dtr_rts
|
||||
.dtr_rts = dtr_rts
|
||||
};
|
||||
|
||||
static int mgslpc_probe(struct pcmcia_device *link)
|
||||
|
|
@ -2528,13 +2528,16 @@ static int carrier_raised(struct tty_port *port)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void raise_dtr_rts(struct tty_port *port)
|
||||
static void dtr_rts(struct tty_port *port, int onoff)
|
||||
{
|
||||
MGSLPC_INFO *info = container_of(port, MGSLPC_INFO, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
if (onoff)
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
else
|
||||
info->serial_signals &= ~SerialSignal_RTS + SerialSignal_DTR;
|
||||
set_signals(info);
|
||||
spin_unlock_irqrestore(&info->lock,flags);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@
|
|||
|
||||
#include <asm/system.h>
|
||||
|
||||
/* These are global because they are accessed in tty_io.c */
|
||||
#ifdef CONFIG_UNIX98_PTYS
|
||||
static struct tty_driver *ptm_driver;
|
||||
static struct tty_driver *pts_driver;
|
||||
|
|
@ -111,7 +110,7 @@ static int pty_write(struct tty_struct *tty, const unsigned char *buf,
|
|||
c = to->receive_room;
|
||||
if (c > count)
|
||||
c = count;
|
||||
to->ldisc.ops->receive_buf(to, buf, NULL, c);
|
||||
to->ldisc->ops->receive_buf(to, buf, NULL, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
|
@ -149,11 +148,11 @@ static int pty_chars_in_buffer(struct tty_struct *tty)
|
|||
int count;
|
||||
|
||||
/* We should get the line discipline lock for "tty->link" */
|
||||
if (!to || !to->ldisc.ops->chars_in_buffer)
|
||||
if (!to || !to->ldisc->ops->chars_in_buffer)
|
||||
return 0;
|
||||
|
||||
/* The ldisc must report 0 if no characters available to be read */
|
||||
count = to->ldisc.ops->chars_in_buffer(to);
|
||||
count = to->ldisc->ops->chars_in_buffer(to);
|
||||
|
||||
if (tty->driver->subtype == PTY_TYPE_SLAVE)
|
||||
return count;
|
||||
|
|
@ -187,8 +186,8 @@ static void pty_flush_buffer(struct tty_struct *tty)
|
|||
if (!to)
|
||||
return;
|
||||
|
||||
if (to->ldisc.ops->flush_buffer)
|
||||
to->ldisc.ops->flush_buffer(to);
|
||||
if (to->ldisc->ops->flush_buffer)
|
||||
to->ldisc->ops->flush_buffer(to);
|
||||
|
||||
if (to->packet) {
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ static int raw_open(struct inode *inode, struct file *filp)
|
|||
err = bd_claim(bdev, raw_open);
|
||||
if (err)
|
||||
goto out1;
|
||||
err = set_blocksize(bdev, bdev_hardsect_size(bdev));
|
||||
err = set_blocksize(bdev, bdev_logical_block_size(bdev));
|
||||
if (err)
|
||||
goto out2;
|
||||
filp->f_flags |= O_DIRECT;
|
||||
|
|
|
|||
|
|
@ -872,11 +872,16 @@ static int carrier_raised(struct tty_port *port)
|
|||
return (sGetChanStatusLo(&info->channel) & CD_ACT) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void raise_dtr_rts(struct tty_port *port)
|
||||
static void dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
struct r_port *info = container_of(port, struct r_port, port);
|
||||
sSetDTR(&info->channel);
|
||||
sSetRTS(&info->channel);
|
||||
if (on) {
|
||||
sSetDTR(&info->channel);
|
||||
sSetRTS(&info->channel);
|
||||
} else {
|
||||
sClrDTR(&info->channel);
|
||||
sClrRTS(&info->channel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -934,7 +939,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
|||
/*
|
||||
* Info->count is now 1; so it's safe to sleep now.
|
||||
*/
|
||||
if (!test_bit(ASYNC_INITIALIZED, &port->flags)) {
|
||||
if (!test_bit(ASYNCB_INITIALIZED, &port->flags)) {
|
||||
cp = &info->channel;
|
||||
sSetRxTrigger(cp, TRIG_1);
|
||||
if (sGetChanStatus(cp) & CD_ACT)
|
||||
|
|
@ -958,7 +963,7 @@ static int rp_open(struct tty_struct *tty, struct file *filp)
|
|||
sEnRxFIFO(cp);
|
||||
sEnTransmit(cp);
|
||||
|
||||
set_bit(ASYNC_INITIALIZED, &info->port.flags);
|
||||
set_bit(ASYNCB_INITIALIZED, &info->port.flags);
|
||||
|
||||
/*
|
||||
* Set up the tty->alt_speed kludge
|
||||
|
|
@ -1641,7 +1646,7 @@ static int rp_write(struct tty_struct *tty,
|
|||
/* Write remaining data into the port's xmit_buf */
|
||||
while (1) {
|
||||
/* Hung up ? */
|
||||
if (!test_bit(ASYNC_NORMAL_ACTIVE, &info->port.flags))
|
||||
if (!test_bit(ASYNCB_NORMAL_ACTIVE, &info->port.flags))
|
||||
goto end;
|
||||
c = min(count, XMIT_BUF_SIZE - info->xmit_cnt - 1);
|
||||
c = min(c, XMIT_BUF_SIZE - info->xmit_head);
|
||||
|
|
@ -2250,7 +2255,7 @@ static const struct tty_operations rocket_ops = {
|
|||
|
||||
static const struct tty_port_operations rocket_port_ops = {
|
||||
.carrier_raised = carrier_raised,
|
||||
.raise_dtr_rts = raise_dtr_rts,
|
||||
.dtr_rts = dtr_rts,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -327,7 +327,7 @@ int paste_selection(struct tty_struct *tty)
|
|||
}
|
||||
count = sel_buffer_lth - pasted;
|
||||
count = min(count, tty->receive_room);
|
||||
tty->ldisc.ops->receive_buf(tty, sel_buffer + pasted,
|
||||
tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
|
||||
NULL, count);
|
||||
pasted += count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -772,11 +772,11 @@ static int stl_carrier_raised(struct tty_port *port)
|
|||
return (portp->sigs & TIOCM_CD) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void stl_raise_dtr_rts(struct tty_port *port)
|
||||
static void stl_dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
struct stlport *portp = container_of(port, struct stlport, port);
|
||||
/* Takes brd_lock internally */
|
||||
stl_setsignals(portp, 1, 1);
|
||||
stl_setsignals(portp, on, on);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -2547,7 +2547,7 @@ static const struct tty_operations stl_ops = {
|
|||
|
||||
static const struct tty_port_operations stl_port_ops = {
|
||||
.carrier_raised = stl_carrier_raised,
|
||||
.raise_dtr_rts = stl_raise_dtr_rts,
|
||||
.dtr_rts = stl_dtr_rts,
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -3247,13 +3247,16 @@ static int carrier_raised(struct tty_port *port)
|
|||
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void raise_dtr_rts(struct tty_port *port)
|
||||
static void dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
struct mgsl_struct *info = container_of(port, struct mgsl_struct, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&info->irq_spinlock,flags);
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
if (on)
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
else
|
||||
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
|
||||
usc_set_serial_signals(info);
|
||||
spin_unlock_irqrestore(&info->irq_spinlock,flags);
|
||||
}
|
||||
|
|
@ -4258,7 +4261,7 @@ static void mgsl_add_device( struct mgsl_struct *info )
|
|||
|
||||
static const struct tty_port_operations mgsl_port_ops = {
|
||||
.carrier_raised = carrier_raised,
|
||||
.raise_dtr_rts = raise_dtr_rts,
|
||||
.dtr_rts = dtr_rts,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ struct slgt_desc
|
|||
#define set_desc_next(a,b) (a).next = cpu_to_le32((unsigned int)(b))
|
||||
#define set_desc_count(a,b)(a).count = cpu_to_le16((unsigned short)(b))
|
||||
#define set_desc_eof(a,b) (a).status = cpu_to_le16((b) ? (le16_to_cpu((a).status) | BIT0) : (le16_to_cpu((a).status) & ~BIT0))
|
||||
#define set_desc_status(a, b) (a).status = cpu_to_le16((unsigned short)(b))
|
||||
#define desc_count(a) (le16_to_cpu((a).count))
|
||||
#define desc_status(a) (le16_to_cpu((a).status))
|
||||
#define desc_complete(a) (le16_to_cpu((a).status) & BIT15)
|
||||
|
|
@ -297,6 +298,7 @@ struct slgt_info {
|
|||
u32 max_frame_size; /* as set by device config */
|
||||
|
||||
unsigned int rbuf_fill_level;
|
||||
unsigned int rx_pio;
|
||||
unsigned int if_mode;
|
||||
unsigned int base_clock;
|
||||
|
||||
|
|
@ -331,6 +333,8 @@ struct slgt_info {
|
|||
struct slgt_desc *rbufs;
|
||||
unsigned int rbuf_current;
|
||||
unsigned int rbuf_index;
|
||||
unsigned int rbuf_fill_index;
|
||||
unsigned short rbuf_fill_count;
|
||||
|
||||
unsigned int tbuf_count;
|
||||
struct slgt_desc *tbufs;
|
||||
|
|
@ -2110,6 +2114,40 @@ static void ri_change(struct slgt_info *info, unsigned short status)
|
|||
info->pending_bh |= BH_STATUS;
|
||||
}
|
||||
|
||||
static void isr_rxdata(struct slgt_info *info)
|
||||
{
|
||||
unsigned int count = info->rbuf_fill_count;
|
||||
unsigned int i = info->rbuf_fill_index;
|
||||
unsigned short reg;
|
||||
|
||||
while (rd_reg16(info, SSR) & IRQ_RXDATA) {
|
||||
reg = rd_reg16(info, RDR);
|
||||
DBGISR(("isr_rxdata %s RDR=%04X\n", info->device_name, reg));
|
||||
if (desc_complete(info->rbufs[i])) {
|
||||
/* all buffers full */
|
||||
rx_stop(info);
|
||||
info->rx_restart = 1;
|
||||
continue;
|
||||
}
|
||||
info->rbufs[i].buf[count++] = (unsigned char)reg;
|
||||
/* async mode saves status byte to buffer for each data byte */
|
||||
if (info->params.mode == MGSL_MODE_ASYNC)
|
||||
info->rbufs[i].buf[count++] = (unsigned char)(reg >> 8);
|
||||
if (count == info->rbuf_fill_level || (reg & BIT10)) {
|
||||
/* buffer full or end of frame */
|
||||
set_desc_count(info->rbufs[i], count);
|
||||
set_desc_status(info->rbufs[i], BIT15 | (reg >> 8));
|
||||
info->rbuf_fill_count = count = 0;
|
||||
if (++i == info->rbuf_count)
|
||||
i = 0;
|
||||
info->pending_bh |= BH_RECEIVE;
|
||||
}
|
||||
}
|
||||
|
||||
info->rbuf_fill_index = i;
|
||||
info->rbuf_fill_count = count;
|
||||
}
|
||||
|
||||
static void isr_serial(struct slgt_info *info)
|
||||
{
|
||||
unsigned short status = rd_reg16(info, SSR);
|
||||
|
|
@ -2125,6 +2163,8 @@ static void isr_serial(struct slgt_info *info)
|
|||
if (info->tx_count)
|
||||
isr_txeom(info, status);
|
||||
}
|
||||
if (info->rx_pio && (status & IRQ_RXDATA))
|
||||
isr_rxdata(info);
|
||||
if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {
|
||||
info->icount.brk++;
|
||||
/* process break detection if tty control allows */
|
||||
|
|
@ -2141,7 +2181,8 @@ static void isr_serial(struct slgt_info *info)
|
|||
} else {
|
||||
if (status & (IRQ_TXIDLE + IRQ_TXUNDER))
|
||||
isr_txeom(info, status);
|
||||
|
||||
if (info->rx_pio && (status & IRQ_RXDATA))
|
||||
isr_rxdata(info);
|
||||
if (status & IRQ_RXIDLE) {
|
||||
if (status & RXIDLE)
|
||||
info->icount.rxidle++;
|
||||
|
|
@ -2642,6 +2683,10 @@ static int rx_enable(struct slgt_info *info, int enable)
|
|||
return -EINVAL;
|
||||
}
|
||||
info->rbuf_fill_level = rbuf_fill_level;
|
||||
if (rbuf_fill_level < 128)
|
||||
info->rx_pio = 1; /* PIO mode */
|
||||
else
|
||||
info->rx_pio = 0; /* DMA mode */
|
||||
rx_stop(info); /* restart receiver to use new fill level */
|
||||
}
|
||||
|
||||
|
|
@ -3099,13 +3144,16 @@ static int carrier_raised(struct tty_port *port)
|
|||
return (info->signals & SerialSignal_DCD) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void raise_dtr_rts(struct tty_port *port)
|
||||
static void dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct slgt_info *info = container_of(port, struct slgt_info, port);
|
||||
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
if (on)
|
||||
info->signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
else
|
||||
info->signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
|
||||
set_signals(info);
|
||||
spin_unlock_irqrestore(&info->lock,flags);
|
||||
}
|
||||
|
|
@ -3419,7 +3467,7 @@ static void add_device(struct slgt_info *info)
|
|||
|
||||
static const struct tty_port_operations slgt_port_ops = {
|
||||
.carrier_raised = carrier_raised,
|
||||
.raise_dtr_rts = raise_dtr_rts,
|
||||
.dtr_rts = dtr_rts,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -3841,15 +3889,27 @@ static void rx_start(struct slgt_info *info)
|
|||
rdma_reset(info);
|
||||
reset_rbufs(info);
|
||||
|
||||
/* set 1st descriptor address */
|
||||
wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
|
||||
|
||||
if (info->params.mode != MGSL_MODE_ASYNC) {
|
||||
/* enable rx DMA and DMA interrupt */
|
||||
wr_reg32(info, RDCSR, (BIT2 + BIT0));
|
||||
if (info->rx_pio) {
|
||||
/* rx request when rx FIFO not empty */
|
||||
wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) & ~BIT14));
|
||||
slgt_irq_on(info, IRQ_RXDATA);
|
||||
if (info->params.mode == MGSL_MODE_ASYNC) {
|
||||
/* enable saving of rx status */
|
||||
wr_reg32(info, RDCSR, BIT6);
|
||||
}
|
||||
} else {
|
||||
/* enable saving of rx status, rx DMA and DMA interrupt */
|
||||
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
|
||||
/* rx request when rx FIFO half full */
|
||||
wr_reg16(info, SCR, (unsigned short)(rd_reg16(info, SCR) | BIT14));
|
||||
/* set 1st descriptor address */
|
||||
wr_reg32(info, RDDAR, info->rbufs[0].pdesc);
|
||||
|
||||
if (info->params.mode != MGSL_MODE_ASYNC) {
|
||||
/* enable rx DMA and DMA interrupt */
|
||||
wr_reg32(info, RDCSR, (BIT2 + BIT0));
|
||||
} else {
|
||||
/* enable saving of rx status, rx DMA and DMA interrupt */
|
||||
wr_reg32(info, RDCSR, (BIT6 + BIT2 + BIT0));
|
||||
}
|
||||
}
|
||||
|
||||
slgt_irq_on(info, IRQ_RXOVER);
|
||||
|
|
@ -4467,6 +4527,8 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
|
|||
static void reset_rbufs(struct slgt_info *info)
|
||||
{
|
||||
free_rbufs(info, 0, info->rbuf_count - 1);
|
||||
info->rbuf_fill_index = 0;
|
||||
info->rbuf_fill_count = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -3277,13 +3277,16 @@ static int carrier_raised(struct tty_port *port)
|
|||
return (info->serial_signals & SerialSignal_DCD) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void raise_dtr_rts(struct tty_port *port)
|
||||
static void dtr_rts(struct tty_port *port, int on)
|
||||
{
|
||||
SLMP_INFO *info = container_of(port, SLMP_INFO, port);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&info->lock,flags);
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
if (on)
|
||||
info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR;
|
||||
else
|
||||
info->serial_signals &= ~(SerialSignal_RTS + SerialSignal_DTR);
|
||||
set_signals(info);
|
||||
spin_unlock_irqrestore(&info->lock,flags);
|
||||
}
|
||||
|
|
@ -3746,7 +3749,7 @@ static void add_device(SLMP_INFO *info)
|
|||
|
||||
static const struct tty_port_operations port_ops = {
|
||||
.carrier_raised = carrier_raised,
|
||||
.raise_dtr_rts = raise_dtr_rts,
|
||||
.dtr_rts = dtr_rts,
|
||||
};
|
||||
|
||||
/* Allocate and initialize a device instance structure
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <linux/kbd_kern.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/quotaops.h>
|
||||
#include <linux/perf_counter.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/suspend.h>
|
||||
|
|
@ -243,6 +244,7 @@ static void sysrq_handle_showregs(int key, struct tty_struct *tty)
|
|||
struct pt_regs *regs = get_irq_regs();
|
||||
if (regs)
|
||||
show_regs(regs);
|
||||
perf_counter_print_debug();
|
||||
}
|
||||
static struct sysrq_key_op sysrq_showregs_op = {
|
||||
.handler = sysrq_handle_showregs,
|
||||
|
|
|
|||
|
|
@ -212,7 +212,8 @@ static int get_event_name(char *dest, struct tcpa_event *event,
|
|||
unsigned char * event_entry)
|
||||
{
|
||||
const char *name = "";
|
||||
char data[40] = "";
|
||||
/* 41 so there is room for 40 data and 1 nul */
|
||||
char data[41] = "";
|
||||
int i, n_len = 0, d_len = 0;
|
||||
struct tcpa_pc_event *pc_event;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,7 @@ static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor,
|
|||
buf = kmalloc(sizeof(*buf), GFP_KERNEL);
|
||||
if (!buf)
|
||||
goto err;
|
||||
if (PAGE_SIZE != N_TTY_BUF_SIZE)
|
||||
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
|
||||
else
|
||||
buf->data = (unsigned char *)__get_free_page(GFP_KERNEL);
|
||||
buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL);
|
||||
if (!buf->data)
|
||||
goto err_buf;
|
||||
atomic_set(&buf->count, 1);
|
||||
|
|
@ -52,10 +49,7 @@ err:
|
|||
static void tty_audit_buf_free(struct tty_audit_buf *buf)
|
||||
{
|
||||
WARN_ON(buf->valid != 0);
|
||||
if (PAGE_SIZE != N_TTY_BUF_SIZE)
|
||||
kfree(buf->data);
|
||||
else
|
||||
free_page((unsigned long)buf->data);
|
||||
kfree(buf->data);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
|
|||
struct tty_driver *p, *res = NULL;
|
||||
int tty_line = 0;
|
||||
int len;
|
||||
char *str;
|
||||
char *str, *stp;
|
||||
|
||||
for (str = name; *str; str++)
|
||||
if ((*str >= '0' && *str <= '9') || *str == ',')
|
||||
|
|
@ -311,13 +311,14 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
|
|||
list_for_each_entry(p, &tty_drivers, tty_drivers) {
|
||||
if (strncmp(name, p->name, len) != 0)
|
||||
continue;
|
||||
if (*str == ',')
|
||||
str++;
|
||||
if (*str == '\0')
|
||||
str = NULL;
|
||||
stp = str;
|
||||
if (*stp == ',')
|
||||
stp++;
|
||||
if (*stp == '\0')
|
||||
stp = NULL;
|
||||
|
||||
if (tty_line >= 0 && tty_line <= p->num && p->ops &&
|
||||
p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
|
||||
p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) {
|
||||
res = tty_driver_kref_get(p);
|
||||
*line = tty_line;
|
||||
break;
|
||||
|
|
@ -469,43 +470,6 @@ void tty_wakeup(struct tty_struct *tty)
|
|||
|
||||
EXPORT_SYMBOL_GPL(tty_wakeup);
|
||||
|
||||
/**
|
||||
* tty_ldisc_flush - flush line discipline queue
|
||||
* @tty: tty
|
||||
*
|
||||
* Flush the line discipline queue (if any) for this tty. If there
|
||||
* is no line discipline active this is a no-op.
|
||||
*/
|
||||
|
||||
void tty_ldisc_flush(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld = tty_ldisc_ref(tty);
|
||||
if (ld) {
|
||||
if (ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
tty_buffer_flush(tty);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
|
||||
|
||||
/**
|
||||
* tty_reset_termios - reset terminal state
|
||||
* @tty: tty to reset
|
||||
*
|
||||
* Restore a terminal to the driver default state
|
||||
*/
|
||||
|
||||
static void tty_reset_termios(struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
*tty->termios = tty->driver->init_termios;
|
||||
tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
|
||||
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* do_tty_hangup - actual handler for hangup events
|
||||
* @work: tty device
|
||||
|
|
@ -535,7 +499,6 @@ static void do_tty_hangup(struct work_struct *work)
|
|||
struct file *cons_filp = NULL;
|
||||
struct file *filp, *f = NULL;
|
||||
struct task_struct *p;
|
||||
struct tty_ldisc *ld;
|
||||
int closecount = 0, n;
|
||||
unsigned long flags;
|
||||
int refs = 0;
|
||||
|
|
@ -566,40 +529,8 @@ static void do_tty_hangup(struct work_struct *work)
|
|||
filp->f_op = &hung_up_tty_fops;
|
||||
}
|
||||
file_list_unlock();
|
||||
/*
|
||||
* FIXME! What are the locking issues here? This may me overdoing
|
||||
* things... This question is especially important now that we've
|
||||
* removed the irqlock.
|
||||
*/
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (ld != NULL) {
|
||||
/* We may have no line discipline at this point */
|
||||
if (ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
|
||||
ld->ops->write_wakeup)
|
||||
ld->ops->write_wakeup(tty);
|
||||
if (ld->ops->hangup)
|
||||
ld->ops->hangup(tty);
|
||||
}
|
||||
/*
|
||||
* FIXME: Once we trust the LDISC code better we can wait here for
|
||||
* ldisc completion and fix the driver call race
|
||||
*/
|
||||
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
/*
|
||||
* Shutdown the current line discipline, and reset it to
|
||||
* N_TTY.
|
||||
*/
|
||||
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
|
||||
tty_reset_termios(tty);
|
||||
/* Defer ldisc switch */
|
||||
/* tty_deferred_ldisc_switch(N_TTY);
|
||||
|
||||
This should get done automatically when the port closes and
|
||||
tty_release is called */
|
||||
tty_ldisc_hangup(tty);
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
if (tty->session) {
|
||||
|
|
@ -628,12 +559,15 @@ static void do_tty_hangup(struct work_struct *work)
|
|||
read_unlock(&tasklist_lock);
|
||||
|
||||
spin_lock_irqsave(&tty->ctrl_lock, flags);
|
||||
tty->flags = 0;
|
||||
clear_bit(TTY_THROTTLED, &tty->flags);
|
||||
clear_bit(TTY_PUSH, &tty->flags);
|
||||
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
|
||||
put_pid(tty->session);
|
||||
put_pid(tty->pgrp);
|
||||
tty->session = NULL;
|
||||
tty->pgrp = NULL;
|
||||
tty->ctrl_status = 0;
|
||||
set_bit(TTY_HUPPED, &tty->flags);
|
||||
spin_unlock_irqrestore(&tty->ctrl_lock, flags);
|
||||
|
||||
/* Account for the p->signal references we killed */
|
||||
|
|
@ -659,10 +593,7 @@ static void do_tty_hangup(struct work_struct *work)
|
|||
* can't yet guarantee all that.
|
||||
*/
|
||||
set_bit(TTY_HUPPED, &tty->flags);
|
||||
if (ld) {
|
||||
tty_ldisc_enable(tty);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
tty_ldisc_enable(tty);
|
||||
unlock_kernel();
|
||||
if (f)
|
||||
fput(f);
|
||||
|
|
@ -2480,6 +2411,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
|
|||
return tty->ops->tiocmset(tty, file, set, clear);
|
||||
}
|
||||
|
||||
struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
tty = tty->link;
|
||||
return tty;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_pair_get_tty);
|
||||
|
||||
struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
|
||||
{
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
return tty;
|
||||
return tty->link;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_pair_get_pty);
|
||||
|
||||
/*
|
||||
* Split this up, as gcc can choke on it otherwise..
|
||||
*/
|
||||
|
|
@ -2495,11 +2444,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
|
||||
return -EINVAL;
|
||||
|
||||
real_tty = tty;
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
real_tty = tty->link;
|
||||
|
||||
real_tty = tty_pair_get_tty(tty);
|
||||
|
||||
/*
|
||||
* Factor out some common prep work
|
||||
|
|
@ -2555,7 +2500,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
|||
case TIOCGSID:
|
||||
return tiocgsid(tty, real_tty, p);
|
||||
case TIOCGETD:
|
||||
return put_user(tty->ldisc.ops->num, (int __user *)p);
|
||||
return put_user(tty->ldisc->ops->num, (int __user *)p);
|
||||
case TIOCSETD:
|
||||
return tiocsetd(tty, p);
|
||||
/*
|
||||
|
|
@ -2770,6 +2715,7 @@ void initialize_tty_struct(struct tty_struct *tty,
|
|||
tty->buf.head = tty->buf.tail = NULL;
|
||||
tty_buffer_init(tty);
|
||||
mutex_init(&tty->termios_mutex);
|
||||
mutex_init(&tty->ldisc_mutex);
|
||||
init_waitqueue_head(&tty->write_wait);
|
||||
init_waitqueue_head(&tty->read_wait);
|
||||
INIT_WORK(&tty->hangup_work, do_tty_hangup);
|
||||
|
|
|
|||
|
|
@ -97,14 +97,19 @@ EXPORT_SYMBOL(tty_driver_flush_buffer);
|
|||
* @tty: terminal
|
||||
*
|
||||
* Indicate that a tty should stop transmitting data down the stack.
|
||||
* Takes the termios mutex to protect against parallel throttle/unthrottle
|
||||
* and also to ensure the driver can consistently reference its own
|
||||
* termios data at this point when implementing software flow control.
|
||||
*/
|
||||
|
||||
void tty_throttle(struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
/* check TTY_THROTTLED first so it indicates our state */
|
||||
if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
tty->ops->throttle)
|
||||
tty->ops->throttle(tty);
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_throttle);
|
||||
|
||||
|
|
@ -113,13 +118,21 @@ EXPORT_SYMBOL(tty_throttle);
|
|||
* @tty: terminal
|
||||
*
|
||||
* Indicate that a tty may continue transmitting data down the stack.
|
||||
* Takes the termios mutex to protect against parallel throttle/unthrottle
|
||||
* and also to ensure the driver can consistently reference its own
|
||||
* termios data at this point when implementing software flow control.
|
||||
*
|
||||
* Drivers should however remember that the stack can issue a throttle,
|
||||
* then change flow control method, then unthrottle.
|
||||
*/
|
||||
|
||||
void tty_unthrottle(struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) &&
|
||||
tty->ops->unthrottle)
|
||||
tty->ops->unthrottle(tty);
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_unthrottle);
|
||||
|
||||
|
|
@ -613,9 +626,25 @@ static int set_termios(struct tty_struct *tty, void __user *arg, int opt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void copy_termios(struct tty_struct *tty, struct ktermios *kterm)
|
||||
{
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
memcpy(kterm, tty->termios, sizeof(struct ktermios));
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
|
||||
static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm)
|
||||
{
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
memcpy(kterm, tty->termios_locked, sizeof(struct ktermios));
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
|
||||
static int get_termio(struct tty_struct *tty, struct termio __user *termio)
|
||||
{
|
||||
if (kernel_termios_to_user_termio(termio, tty->termios))
|
||||
struct ktermios kterm;
|
||||
copy_termios(tty, &kterm);
|
||||
if (kernel_termios_to_user_termio(termio, &kterm))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -917,6 +946,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||
struct tty_struct *real_tty;
|
||||
void __user *p = (void __user *)arg;
|
||||
int ret = 0;
|
||||
struct ktermios kterm;
|
||||
struct termiox ktermx;
|
||||
|
||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||
|
|
@ -952,23 +983,20 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||
return set_termios(real_tty, p, TERMIOS_OLD);
|
||||
#ifndef TCGETS2
|
||||
case TCGETS:
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
|
||||
copy_termios(real_tty, &kterm);
|
||||
if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
|
||||
ret = -EFAULT;
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
#else
|
||||
case TCGETS:
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios))
|
||||
copy_termios(real_tty, &kterm);
|
||||
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
|
||||
ret = -EFAULT;
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
case TCGETS2:
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, real_tty->termios))
|
||||
copy_termios(real_tty, &kterm);
|
||||
if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm))
|
||||
ret = -EFAULT;
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
case TCSETSF2:
|
||||
return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT);
|
||||
|
|
@ -987,34 +1015,36 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||
return set_termios(real_tty, p, TERMIOS_TERMIO);
|
||||
#ifndef TCGETS2
|
||||
case TIOCGLCKTRMIOS:
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
|
||||
copy_termios_locked(real_tty, &kterm);
|
||||
if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm))
|
||||
ret = -EFAULT;
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
case TIOCSLCKTRMIOS:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return -EPERM;
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (user_termios_to_kernel_termios(real_tty->termios_locked,
|
||||
copy_termios_locked(real_tty, &kterm);
|
||||
if (user_termios_to_kernel_termios(&kterm,
|
||||
(struct termios __user *) arg))
|
||||
ret = -EFAULT;
|
||||
return -EFAULT;
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
return 0;
|
||||
#else
|
||||
case TIOCGLCKTRMIOS:
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, real_tty->termios_locked))
|
||||
copy_termios_locked(real_tty, &kterm);
|
||||
if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm))
|
||||
ret = -EFAULT;
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
case TIOCSLCKTRMIOS:
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
ret = -EPERM;
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (user_termios_to_kernel_termios_1(real_tty->termios_locked,
|
||||
return -EPERM;
|
||||
copy_termios_locked(real_tty, &kterm);
|
||||
if (user_termios_to_kernel_termios_1(&kterm,
|
||||
(struct termios __user *) arg))
|
||||
ret = -EFAULT;
|
||||
return -EFAULT;
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
memcpy(real_tty->termios_locked, &kterm, sizeof(struct ktermios));
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
#endif
|
||||
|
|
@ -1023,9 +1053,10 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||
if (real_tty->termiox == NULL)
|
||||
return -EINVAL;
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
if (copy_to_user(p, real_tty->termiox, sizeof(struct termiox)))
|
||||
ret = -EFAULT;
|
||||
memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox));
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
|
||||
ret = -EFAULT;
|
||||
return ret;
|
||||
case TCSETX:
|
||||
return set_termiox(real_tty, p, 0);
|
||||
|
|
@ -1035,10 +1066,9 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
|
|||
return set_termiox(real_tty, p, TERMIOS_FLUSH);
|
||||
#endif
|
||||
case TIOCGSOFTCAR:
|
||||
mutex_lock(&real_tty->termios_mutex);
|
||||
ret = put_user(C_CLOCAL(real_tty) ? 1 : 0,
|
||||
copy_termios(real_tty, &kterm);
|
||||
ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0,
|
||||
(int __user *)arg);
|
||||
mutex_unlock(&real_tty->termios_mutex);
|
||||
return ret;
|
||||
case TIOCSSOFTCAR:
|
||||
if (get_user(arg, (unsigned int __user *) arg))
|
||||
|
|
|
|||
|
|
@ -115,19 +115,22 @@ EXPORT_SYMBOL(tty_unregister_ldisc);
|
|||
/**
|
||||
* tty_ldisc_try_get - try and reference an ldisc
|
||||
* @disc: ldisc number
|
||||
* @ld: tty ldisc structure to complete
|
||||
*
|
||||
* Attempt to open and lock a line discipline into place. Return
|
||||
* the line discipline refcounted and assigned in ld. On an error
|
||||
* report the error code back
|
||||
* the line discipline refcounted or an error.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
|
||||
static struct tty_ldisc *tty_ldisc_try_get(int disc)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_ldisc *ld;
|
||||
struct tty_ldisc_ops *ldops;
|
||||
int err = -EINVAL;
|
||||
|
||||
|
||||
ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
|
||||
if (ld == NULL)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld->ops = NULL;
|
||||
ldops = tty_ldiscs[disc];
|
||||
|
|
@ -140,17 +143,19 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
|
|||
/* lock it */
|
||||
ldops->refcount++;
|
||||
ld->ops = ldops;
|
||||
ld->refcount = 0;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
return err;
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_get - take a reference to an ldisc
|
||||
* @disc: ldisc number
|
||||
* @ld: tty line discipline structure to use
|
||||
*
|
||||
* Takes a reference to a line discipline. Deals with refcounts and
|
||||
* module locking counts. Returns NULL if the discipline is not available.
|
||||
|
|
@ -161,52 +166,54 @@ static int tty_ldisc_try_get(int disc, struct tty_ldisc *ld)
|
|||
* takes tty_ldisc_lock to guard against ldisc races
|
||||
*/
|
||||
|
||||
static int tty_ldisc_get(int disc, struct tty_ldisc *ld)
|
||||
static struct tty_ldisc *tty_ldisc_get(int disc)
|
||||
{
|
||||
int err;
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
if (disc < N_TTY || disc >= NR_LDISCS)
|
||||
return -EINVAL;
|
||||
err = tty_ldisc_try_get(disc, ld);
|
||||
if (err < 0) {
|
||||
return ERR_PTR(-EINVAL);
|
||||
ld = tty_ldisc_try_get(disc);
|
||||
if (IS_ERR(ld)) {
|
||||
request_module("tty-ldisc-%d", disc);
|
||||
err = tty_ldisc_try_get(disc, ld);
|
||||
ld = tty_ldisc_try_get(disc);
|
||||
}
|
||||
return err;
|
||||
return ld;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_put - drop ldisc reference
|
||||
* @disc: ldisc number
|
||||
* @ld: ldisc
|
||||
*
|
||||
* Drop a reference to a line discipline. Manage refcounts and
|
||||
* module usage counts
|
||||
* module usage counts. Free the ldisc once the recount hits zero.
|
||||
*
|
||||
* Locking:
|
||||
* takes tty_ldisc_lock to guard against ldisc races
|
||||
*/
|
||||
|
||||
static void tty_ldisc_put(struct tty_ldisc_ops *ld)
|
||||
static void tty_ldisc_put(struct tty_ldisc *ld)
|
||||
{
|
||||
unsigned long flags;
|
||||
int disc = ld->num;
|
||||
int disc = ld->ops->num;
|
||||
struct tty_ldisc_ops *ldo;
|
||||
|
||||
BUG_ON(disc < N_TTY || disc >= NR_LDISCS);
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld = tty_ldiscs[disc];
|
||||
BUG_ON(ld->refcount == 0);
|
||||
ld->refcount--;
|
||||
module_put(ld->owner);
|
||||
ldo = tty_ldiscs[disc];
|
||||
BUG_ON(ldo->refcount == 0);
|
||||
ldo->refcount--;
|
||||
module_put(ldo->owner);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
kfree(ld);
|
||||
}
|
||||
|
||||
static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
|
||||
static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
return (*pos < NR_LDISCS) ? pos : NULL;
|
||||
}
|
||||
|
||||
static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
(*pos)++;
|
||||
return (*pos < NR_LDISCS) ? pos : NULL;
|
||||
|
|
@ -219,12 +226,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
|
|||
static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
|
||||
{
|
||||
int i = *(loff_t *)v;
|
||||
struct tty_ldisc ld;
|
||||
|
||||
if (tty_ldisc_get(i, &ld) < 0)
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
ld = tty_ldisc_try_get(i);
|
||||
if (IS_ERR(ld))
|
||||
return 0;
|
||||
seq_printf(m, "%-10s %2d\n", ld.ops->name ? ld.ops->name : "???", i);
|
||||
tty_ldisc_put(ld.ops);
|
||||
seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i);
|
||||
tty_ldisc_put(ld);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -263,8 +271,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
|
|||
|
||||
static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
ld->refcount = 0;
|
||||
tty->ldisc = *ld;
|
||||
tty->ldisc = ld;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -286,7 +293,7 @@ static int tty_ldisc_try(struct tty_struct *tty)
|
|||
int ret = 0;
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
ld = &tty->ldisc;
|
||||
ld = tty->ldisc;
|
||||
if (test_bit(TTY_LDISC, &tty->flags)) {
|
||||
ld->refcount++;
|
||||
ret = 1;
|
||||
|
|
@ -315,10 +322,9 @@ struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
|
|||
{
|
||||
/* wait_event is a macro */
|
||||
wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
|
||||
WARN_ON(tty->ldisc.refcount == 0);
|
||||
return &tty->ldisc;
|
||||
WARN_ON(tty->ldisc->refcount == 0);
|
||||
return tty->ldisc;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
|
||||
|
||||
/**
|
||||
|
|
@ -335,10 +341,9 @@ EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
|
|||
struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
|
||||
{
|
||||
if (tty_ldisc_try(tty))
|
||||
return &tty->ldisc;
|
||||
return tty->ldisc;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_ref);
|
||||
|
||||
/**
|
||||
|
|
@ -366,7 +371,6 @@ void tty_ldisc_deref(struct tty_ldisc *ld)
|
|||
wake_up(&tty_ldisc_wait);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_deref);
|
||||
|
||||
/**
|
||||
|
|
@ -388,6 +392,26 @@ void tty_ldisc_enable(struct tty_struct *tty)
|
|||
wake_up(&tty_ldisc_wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_flush - flush line discipline queue
|
||||
* @tty: tty
|
||||
*
|
||||
* Flush the line discipline queue (if any) for this tty. If there
|
||||
* is no line discipline active this is a no-op.
|
||||
*/
|
||||
|
||||
void tty_ldisc_flush(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld = tty_ldisc_ref(tty);
|
||||
if (ld) {
|
||||
if (ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
tty_buffer_flush(tty);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tty_ldisc_flush);
|
||||
|
||||
/**
|
||||
* tty_set_termios_ldisc - set ldisc field
|
||||
* @tty: tty structure
|
||||
|
|
@ -407,6 +431,39 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
|
|||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_open - open a line discipline
|
||||
* @tty: tty we are opening the ldisc on
|
||||
* @ld: discipline to open
|
||||
*
|
||||
* A helper opening method. Also a convenient debugging and check
|
||||
* point.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||
if (ld->ops->open)
|
||||
return ld->ops->open(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_close - close a line discipline
|
||||
* @tty: tty we are opening the ldisc on
|
||||
* @ld: discipline to close
|
||||
*
|
||||
* A helper close method. Also a convenient debugging and check
|
||||
* point.
|
||||
*/
|
||||
|
||||
static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld)
|
||||
{
|
||||
WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags));
|
||||
clear_bit(TTY_LDISC_OPEN, &tty->flags);
|
||||
if (ld->ops->close)
|
||||
ld->ops->close(tty);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_restore - helper for tty ldisc change
|
||||
|
|
@ -420,66 +477,136 @@ static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
|
|||
static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||
{
|
||||
char buf[64];
|
||||
struct tty_ldisc new_ldisc;
|
||||
struct tty_ldisc *new_ldisc;
|
||||
int r;
|
||||
|
||||
/* There is an outstanding reference here so this is safe */
|
||||
tty_ldisc_get(old->ops->num, old);
|
||||
old = tty_ldisc_get(old->ops->num);
|
||||
WARN_ON(IS_ERR(old));
|
||||
tty_ldisc_assign(tty, old);
|
||||
tty_set_termios_ldisc(tty, old->ops->num);
|
||||
if (old->ops->open && (old->ops->open(tty) < 0)) {
|
||||
tty_ldisc_put(old->ops);
|
||||
if (tty_ldisc_open(tty, old) < 0) {
|
||||
tty_ldisc_put(old);
|
||||
/* This driver is always present */
|
||||
if (tty_ldisc_get(N_TTY, &new_ldisc) < 0)
|
||||
new_ldisc = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(new_ldisc))
|
||||
panic("n_tty: get");
|
||||
tty_ldisc_assign(tty, &new_ldisc);
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
if (new_ldisc.ops->open) {
|
||||
int r = new_ldisc.ops->open(tty);
|
||||
if (r < 0)
|
||||
panic("Couldn't open N_TTY ldisc for "
|
||||
"%s --- error %d.",
|
||||
tty_name(tty, buf), r);
|
||||
}
|
||||
r = tty_ldisc_open(tty, new_ldisc);
|
||||
if (r < 0)
|
||||
panic("Couldn't open N_TTY ldisc for "
|
||||
"%s --- error %d.",
|
||||
tty_name(tty, buf), r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_halt - shut down the line discipline
|
||||
* @tty: tty device
|
||||
*
|
||||
* Shut down the line discipline and work queue for this tty device.
|
||||
* The TTY_LDISC flag being cleared ensures no further references can
|
||||
* be obtained while the delayed work queue halt ensures that no more
|
||||
* data is fed to the ldisc.
|
||||
*
|
||||
* In order to wait for any existing references to complete see
|
||||
* tty_ldisc_wait_idle.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_halt(struct tty_struct *tty)
|
||||
{
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
return cancel_delayed_work(&tty->buf.work);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_wait_idle - wait for the ldisc to become idle
|
||||
* @tty: tty to wait for
|
||||
*
|
||||
* Wait for the line discipline to become idle. The discipline must
|
||||
* have been halted for this to guarantee it remains idle.
|
||||
*
|
||||
* tty_ldisc_lock protects the ref counts currently.
|
||||
*/
|
||||
|
||||
static int tty_ldisc_wait_idle(struct tty_struct *tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
while (tty->ldisc->refcount) {
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
if (wait_event_timeout(tty_ldisc_wait,
|
||||
tty->ldisc->refcount == 0, 5 * HZ) == 0)
|
||||
return -EBUSY;
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_set_ldisc - set line discipline
|
||||
* @tty: the terminal to set
|
||||
* @ldisc: the line discipline
|
||||
*
|
||||
* Set the discipline of a tty line. Must be called from a process
|
||||
* context.
|
||||
* context. The ldisc change logic has to protect itself against any
|
||||
* overlapping ldisc change (including on the other end of pty pairs),
|
||||
* the close of one side of a tty/pty pair, and eventually hangup.
|
||||
*
|
||||
* Locking: takes tty_ldisc_lock.
|
||||
* called functions take termios_mutex
|
||||
* Locking: takes tty_ldisc_lock, termios_mutex
|
||||
*/
|
||||
|
||||
int tty_set_ldisc(struct tty_struct *tty, int ldisc)
|
||||
{
|
||||
int retval;
|
||||
struct tty_ldisc o_ldisc, new_ldisc;
|
||||
int work;
|
||||
unsigned long flags;
|
||||
struct tty_ldisc *o_ldisc, *new_ldisc;
|
||||
int work, o_work = 0;
|
||||
struct tty_struct *o_tty;
|
||||
|
||||
restart:
|
||||
/* This is a bit ugly for now but means we can break the 'ldisc
|
||||
is part of the tty struct' assumption later */
|
||||
retval = tty_ldisc_get(ldisc, &new_ldisc);
|
||||
if (retval)
|
||||
return retval;
|
||||
new_ldisc = tty_ldisc_get(ldisc);
|
||||
if (IS_ERR(new_ldisc))
|
||||
return PTR_ERR(new_ldisc);
|
||||
|
||||
/*
|
||||
* We need to look at the tty locking here for pty/tty pairs
|
||||
* when both sides try to change in parallel.
|
||||
*/
|
||||
|
||||
o_tty = tty->link; /* o_tty is the pty side or NULL */
|
||||
|
||||
|
||||
/*
|
||||
* Check the no-op case
|
||||
*/
|
||||
|
||||
if (tty->ldisc->ops->num == ldisc) {
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Problem: What do we do if this blocks ?
|
||||
* We could deadlock here
|
||||
*/
|
||||
|
||||
tty_wait_until_sent(tty, 0);
|
||||
|
||||
if (tty->ldisc.ops->num == ldisc) {
|
||||
tty_ldisc_put(new_ldisc.ops);
|
||||
return 0;
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
|
||||
/*
|
||||
* We could be midstream of another ldisc change which has
|
||||
* dropped the lock during processing. If so we need to wait.
|
||||
*/
|
||||
|
||||
while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
wait_event(tty_ldisc_wait,
|
||||
test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0);
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
}
|
||||
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
|
||||
/*
|
||||
* No more input please, we are switching. The new ldisc
|
||||
|
|
@ -489,8 +616,6 @@ restart:
|
|||
tty->receive_room = 0;
|
||||
|
||||
o_ldisc = tty->ldisc;
|
||||
o_tty = tty->link;
|
||||
|
||||
/*
|
||||
* Make sure we don't change while someone holds a
|
||||
* reference to the line discipline. The TTY_LDISC bit
|
||||
|
|
@ -501,108 +626,181 @@ restart:
|
|||
* with a userspace app continually trying to use the tty in
|
||||
* parallel to the change and re-referencing the tty.
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
if (o_tty)
|
||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
|
||||
if (tty->ldisc.refcount) {
|
||||
/* Free the new ldisc we grabbed. Must drop the lock
|
||||
first. */
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
tty_ldisc_put(o_ldisc.ops);
|
||||
/*
|
||||
* There are several reasons we may be busy, including
|
||||
* random momentary I/O traffic. We must therefore
|
||||
* retry. We could distinguish between blocking ops
|
||||
* and retries if we made tty_ldisc_wait() smarter.
|
||||
* That is up for discussion.
|
||||
*/
|
||||
if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
|
||||
return -ERESTARTSYS;
|
||||
goto restart;
|
||||
}
|
||||
if (o_tty && o_tty->ldisc.refcount) {
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
tty_ldisc_put(o_tty->ldisc.ops);
|
||||
if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
|
||||
return -ERESTARTSYS;
|
||||
goto restart;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If the TTY_LDISC bit is set, then we are racing against
|
||||
* another ldisc change
|
||||
*/
|
||||
if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) {
|
||||
struct tty_ldisc *ld;
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
tty_ldisc_put(new_ldisc.ops);
|
||||
ld = tty_ldisc_ref_wait(tty);
|
||||
tty_ldisc_deref(ld);
|
||||
goto restart;
|
||||
}
|
||||
/*
|
||||
* This flag is used to avoid two parallel ldisc changes. Once
|
||||
* open and close are fine grained locked this may work better
|
||||
* as a mutex shared with the open/close/hup paths
|
||||
*/
|
||||
set_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
work = tty_ldisc_halt(tty);
|
||||
if (o_tty)
|
||||
set_bit(TTY_LDISC_CHANGING, &o_tty->flags);
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
o_work = tty_ldisc_halt(o_tty);
|
||||
|
||||
/*
|
||||
* From this point on we know nobody has an ldisc
|
||||
* usage reference, nor can they obtain one until
|
||||
* we say so later on.
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate.
|
||||
* We must drop the mutex here in case a hangup is also in process.
|
||||
*/
|
||||
|
||||
work = cancel_delayed_work(&tty->buf.work);
|
||||
/*
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate
|
||||
* MUST NOT hold locks here.
|
||||
*/
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
|
||||
flush_scheduled_work();
|
||||
|
||||
/* Let any existing reference holders finish */
|
||||
retval = tty_ldisc_wait_idle(tty);
|
||||
if (retval < 0) {
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
if (test_bit(TTY_HUPPED, &tty->flags)) {
|
||||
/* We were raced by the hangup method. It will have stomped
|
||||
the ldisc data and closed the ldisc down */
|
||||
clear_bit(TTY_LDISC_CHANGING, &tty->flags);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_ldisc_put(new_ldisc);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Shutdown the current discipline. */
|
||||
if (o_ldisc.ops->close)
|
||||
(o_ldisc.ops->close)(tty);
|
||||
tty_ldisc_close(tty, o_ldisc);
|
||||
|
||||
/* Now set up the new line discipline. */
|
||||
tty_ldisc_assign(tty, &new_ldisc);
|
||||
tty_ldisc_assign(tty, new_ldisc);
|
||||
tty_set_termios_ldisc(tty, ldisc);
|
||||
if (new_ldisc.ops->open)
|
||||
retval = (new_ldisc.ops->open)(tty);
|
||||
|
||||
retval = tty_ldisc_open(tty, new_ldisc);
|
||||
if (retval < 0) {
|
||||
tty_ldisc_put(new_ldisc.ops);
|
||||
tty_ldisc_restore(tty, &o_ldisc);
|
||||
/* Back to the old one or N_TTY if we can't */
|
||||
tty_ldisc_put(new_ldisc);
|
||||
tty_ldisc_restore(tty, o_ldisc);
|
||||
}
|
||||
|
||||
/* At this point we hold a reference to the new ldisc and a
|
||||
a reference to the old ldisc. If we ended up flipping back
|
||||
to the existing ldisc we have two references to it */
|
||||
|
||||
if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc)
|
||||
if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc)
|
||||
tty->ops->set_ldisc(tty);
|
||||
|
||||
tty_ldisc_put(o_ldisc.ops);
|
||||
tty_ldisc_put(o_ldisc);
|
||||
|
||||
/*
|
||||
* Allow ldisc referencing to occur as soon as the driver
|
||||
* ldisc callback completes.
|
||||
* Allow ldisc referencing to occur again
|
||||
*/
|
||||
|
||||
tty_ldisc_enable(tty);
|
||||
if (o_tty)
|
||||
tty_ldisc_enable(o_tty);
|
||||
|
||||
/* Restart it in case no characters kick it off. Safe if
|
||||
/* Restart the work queue in case no characters kick it off. Safe if
|
||||
already running */
|
||||
if (work)
|
||||
schedule_delayed_work(&tty->buf.work, 1);
|
||||
if (o_work)
|
||||
schedule_delayed_work(&o_tty->buf.work, 1);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_reset_termios - reset terminal state
|
||||
* @tty: tty to reset
|
||||
*
|
||||
* Restore a terminal to the driver default state.
|
||||
*/
|
||||
|
||||
static void tty_reset_termios(struct tty_struct *tty)
|
||||
{
|
||||
mutex_lock(&tty->termios_mutex);
|
||||
*tty->termios = tty->driver->init_termios;
|
||||
tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
|
||||
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
|
||||
mutex_unlock(&tty->termios_mutex);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tty_ldisc_reinit - reinitialise the tty ldisc
|
||||
* @tty: tty to reinit
|
||||
*
|
||||
* Switch the tty back to N_TTY line discipline and leave the
|
||||
* ldisc state closed
|
||||
*/
|
||||
|
||||
static void tty_ldisc_reinit(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
tty_ldisc_close(tty, tty->ldisc);
|
||||
tty_ldisc_put(tty->ldisc);
|
||||
tty->ldisc = NULL;
|
||||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
ld = tty_ldisc_get(N_TTY);
|
||||
BUG_ON(IS_ERR(ld));
|
||||
tty_ldisc_assign(tty, ld);
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_hangup - hangup ldisc reset
|
||||
* @tty: tty being hung up
|
||||
*
|
||||
* Some tty devices reset their termios when they receive a hangup
|
||||
* event. In that situation we must also switch back to N_TTY properly
|
||||
* before we reset the termios data.
|
||||
*
|
||||
* Locking: We can take the ldisc mutex as the rest of the code is
|
||||
* careful to allow for this.
|
||||
*
|
||||
* In the pty pair case this occurs in the close() path of the
|
||||
* tty itself so we must be careful about locking rules.
|
||||
*/
|
||||
|
||||
void tty_ldisc_hangup(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc *ld;
|
||||
|
||||
/*
|
||||
* FIXME! What are the locking issues here? This may me overdoing
|
||||
* things... This question is especially important now that we've
|
||||
* removed the irqlock.
|
||||
*/
|
||||
ld = tty_ldisc_ref(tty);
|
||||
if (ld != NULL) {
|
||||
/* We may have no line discipline at this point */
|
||||
if (ld->ops->flush_buffer)
|
||||
ld->ops->flush_buffer(tty);
|
||||
tty_driver_flush_buffer(tty);
|
||||
if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
|
||||
ld->ops->write_wakeup)
|
||||
ld->ops->write_wakeup(tty);
|
||||
if (ld->ops->hangup)
|
||||
ld->ops->hangup(tty);
|
||||
tty_ldisc_deref(ld);
|
||||
}
|
||||
/*
|
||||
* FIXME: Once we trust the LDISC code better we can wait here for
|
||||
* ldisc completion and fix the driver call race
|
||||
*/
|
||||
wake_up_interruptible_poll(&tty->write_wait, POLLOUT);
|
||||
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
|
||||
/*
|
||||
* Shutdown the current line discipline, and reset it to
|
||||
* N_TTY.
|
||||
*/
|
||||
if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
|
||||
/* Avoid racing set_ldisc */
|
||||
mutex_lock(&tty->ldisc_mutex);
|
||||
/* Switch back to N_TTY */
|
||||
tty_ldisc_reinit(tty);
|
||||
/* At this point we have a closed ldisc and we want to
|
||||
reopen it. We could defer this to the next open but
|
||||
it means auditing a lot of other paths so this is a FIXME */
|
||||
WARN_ON(tty_ldisc_open(tty, tty->ldisc));
|
||||
tty_ldisc_enable(tty);
|
||||
mutex_unlock(&tty->ldisc_mutex);
|
||||
tty_reset_termios(tty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_setup - open line discipline
|
||||
|
|
@ -610,24 +808,23 @@ restart:
|
|||
* @o_tty: pair tty for pty/tty pairs
|
||||
*
|
||||
* Called during the initial open of a tty/pty pair in order to set up the
|
||||
* line discplines and bind them to the tty.
|
||||
* line disciplines and bind them to the tty. This has no locking issues
|
||||
* as the device isn't yet active.
|
||||
*/
|
||||
|
||||
int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
{
|
||||
struct tty_ldisc *ld = &tty->ldisc;
|
||||
struct tty_ldisc *ld = tty->ldisc;
|
||||
int retval;
|
||||
|
||||
if (ld->ops->open) {
|
||||
retval = (ld->ops->open)(tty);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (o_tty && o_tty->ldisc.ops->open) {
|
||||
retval = (o_tty->ldisc.ops->open)(o_tty);
|
||||
retval = tty_ldisc_open(tty, ld);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (o_tty) {
|
||||
retval = tty_ldisc_open(o_tty, o_tty->ldisc);
|
||||
if (retval) {
|
||||
if (ld->ops->close)
|
||||
(ld->ops->close)(tty);
|
||||
tty_ldisc_close(tty, ld);
|
||||
return retval;
|
||||
}
|
||||
tty_ldisc_enable(o_tty);
|
||||
|
|
@ -635,32 +832,25 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
tty_ldisc_enable(tty);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* tty_ldisc_release - release line discipline
|
||||
* @tty: tty being shut down
|
||||
* @o_tty: pair tty for pty/tty pairs
|
||||
*
|
||||
* Called during the final close of a tty/pty pair in order to shut down the
|
||||
* line discpline layer.
|
||||
* Called during the final close of a tty/pty pair in order to shut down
|
||||
* the line discpline layer. On exit the ldisc assigned is N_TTY and the
|
||||
* ldisc has not been opened.
|
||||
*/
|
||||
|
||||
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct tty_ldisc ld;
|
||||
/*
|
||||
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
|
||||
* kill any delayed work. As this is the final close it does not
|
||||
* race with the set_ldisc code path.
|
||||
*/
|
||||
clear_bit(TTY_LDISC, &tty->flags);
|
||||
cancel_delayed_work(&tty->buf.work);
|
||||
|
||||
/*
|
||||
* Wait for ->hangup_work and ->buf.work handlers to terminate
|
||||
*/
|
||||
|
||||
tty_ldisc_halt(tty);
|
||||
flush_scheduled_work();
|
||||
|
||||
/*
|
||||
|
|
@ -668,38 +858,19 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
* side waiters as the file is closing so user count on the file
|
||||
* side is zero.
|
||||
*/
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
while (tty->ldisc.refcount) {
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
|
||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||
|
||||
tty_ldisc_wait_idle(tty);
|
||||
|
||||
/*
|
||||
* Shutdown the current line discipline, and reset it to N_TTY.
|
||||
*
|
||||
* FIXME: this MUST get fixed for the new reflocking
|
||||
*/
|
||||
if (tty->ldisc.ops->close)
|
||||
(tty->ldisc.ops->close)(tty);
|
||||
tty_ldisc_put(tty->ldisc.ops);
|
||||
|
||||
/*
|
||||
* Switch the line discipline back
|
||||
*/
|
||||
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
||||
tty_ldisc_assign(tty, &ld);
|
||||
tty_set_termios_ldisc(tty, N_TTY);
|
||||
if (o_tty) {
|
||||
/* FIXME: could o_tty be in setldisc here ? */
|
||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||
if (o_tty->ldisc.ops->close)
|
||||
(o_tty->ldisc.ops->close)(o_tty);
|
||||
tty_ldisc_put(o_tty->ldisc.ops);
|
||||
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
||||
tty_ldisc_assign(o_tty, &ld);
|
||||
tty_set_termios_ldisc(o_tty, N_TTY);
|
||||
}
|
||||
tty_ldisc_reinit(tty);
|
||||
/* This will need doing differently if we need to lock */
|
||||
if (o_tty)
|
||||
tty_ldisc_release(o_tty, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -712,10 +883,10 @@ void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
|||
|
||||
void tty_ldisc_init(struct tty_struct *tty)
|
||||
{
|
||||
struct tty_ldisc ld;
|
||||
if (tty_ldisc_get(N_TTY, &ld) < 0)
|
||||
struct tty_ldisc *ld = tty_ldisc_get(N_TTY);
|
||||
if (IS_ERR(ld))
|
||||
panic("n_tty: init_tty");
|
||||
tty_ldisc_assign(tty, &ld);
|
||||
tty_ldisc_assign(tty, ld);
|
||||
}
|
||||
|
||||
void tty_ldisc_begin(void)
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ int tty_port_carrier_raised(struct tty_port *port)
|
|||
EXPORT_SYMBOL(tty_port_carrier_raised);
|
||||
|
||||
/**
|
||||
* tty_port_raise_dtr_rts - Riase DTR/RTS
|
||||
* tty_port_raise_dtr_rts - Raise DTR/RTS
|
||||
* @port: tty port
|
||||
*
|
||||
* Wrapper for the DTR/RTS raise logic. For the moment this is used
|
||||
|
|
@ -147,11 +147,27 @@ EXPORT_SYMBOL(tty_port_carrier_raised);
|
|||
|
||||
void tty_port_raise_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->raise_dtr_rts)
|
||||
port->ops->raise_dtr_rts(port);
|
||||
if (port->ops->dtr_rts)
|
||||
port->ops->dtr_rts(port, 1);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
||||
|
||||
/**
|
||||
* tty_port_lower_dtr_rts - Lower DTR/RTS
|
||||
* @port: tty port
|
||||
*
|
||||
* Wrapper for the DTR/RTS raise logic. For the moment this is used
|
||||
* to hide some internal details. This will eventually become entirely
|
||||
* internal to the tty port.
|
||||
*/
|
||||
|
||||
void tty_port_lower_dtr_rts(struct tty_port *port)
|
||||
{
|
||||
if (port->ops->dtr_rts)
|
||||
port->ops->dtr_rts(port, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_lower_dtr_rts);
|
||||
|
||||
/**
|
||||
* tty_port_block_til_ready - Waiting logic for tty open
|
||||
* @port: the tty port being opened
|
||||
|
|
@ -167,7 +183,7 @@ EXPORT_SYMBOL(tty_port_raise_dtr_rts);
|
|||
* - port flags and counts
|
||||
*
|
||||
* The passed tty_port must implement the carrier_raised method if it can
|
||||
* do carrier detect and the raise_dtr_rts method if it supports software
|
||||
* do carrier detect and the dtr_rts method if it supports software
|
||||
* management of these lines. Note that the dtr/rts raise is done each
|
||||
* iteration as a hangup may have previously dropped them while we wait.
|
||||
*/
|
||||
|
|
@ -182,7 +198,8 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
|
||||
/* block if port is in the process of being closed */
|
||||
if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {
|
||||
interruptible_sleep_on(&port->close_wait);
|
||||
wait_event_interruptible(port->close_wait,
|
||||
!(port->flags & ASYNC_CLOSING));
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
return -EAGAIN;
|
||||
else
|
||||
|
|
@ -205,7 +222,6 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
before the next open may complete */
|
||||
|
||||
retval = 0;
|
||||
add_wait_queue(&port->open_wait, &wait);
|
||||
|
||||
/* The port lock protects the port counts */
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
|
@ -219,7 +235,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
if (tty->termios->c_cflag & CBAUD)
|
||||
tty_port_raise_dtr_rts(port);
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE);
|
||||
/* Check for a hangup or uninitialised port. Return accordingly */
|
||||
if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) {
|
||||
if (port->flags & ASYNC_HUP_NOTIFY)
|
||||
|
|
@ -240,8 +256,7 @@ int tty_port_block_til_ready(struct tty_port *port,
|
|||
}
|
||||
schedule();
|
||||
}
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&port->open_wait, &wait);
|
||||
finish_wait(&port->open_wait, &wait);
|
||||
|
||||
/* Update counts. A parallel hangup will have set count to zero and
|
||||
we must not mess that up further */
|
||||
|
|
@ -292,6 +307,17 @@ int tty_port_close_start(struct tty_port *port, struct tty_struct *tty, struct f
|
|||
if (port->flags & ASYNC_INITIALIZED &&
|
||||
port->closing_wait != ASYNC_CLOSING_WAIT_NONE)
|
||||
tty_wait_until_sent(tty, port->closing_wait);
|
||||
if (port->drain_delay) {
|
||||
unsigned int bps = tty_get_baud_rate(tty);
|
||||
long timeout;
|
||||
|
||||
if (bps > 1200)
|
||||
timeout = max_t(long, (HZ * 10 * port->drain_delay) / bps,
|
||||
HZ / 10);
|
||||
else
|
||||
timeout = 2 * HZ;
|
||||
schedule_timeout_interruptible(timeout);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(tty_port_close_start);
|
||||
|
|
@ -302,6 +328,9 @@ void tty_port_close_end(struct tty_port *port, struct tty_struct *tty)
|
|||
|
||||
tty_ldisc_flush(tty);
|
||||
|
||||
if (tty->termios->c_cflag & HUPCL)
|
||||
tty_port_lower_dtr_rts(port);
|
||||
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
tty->closing = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,6 @@
|
|||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/font.h>
|
||||
#include <linux/bitops.h>
|
||||
|
|
@ -104,6 +103,7 @@
|
|||
#include <linux/io.h>
|
||||
#include <asm/system.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kmemleak.h>
|
||||
|
||||
#define MAX_NR_CON_DRIVER 16
|
||||
|
||||
|
|
@ -2875,14 +2875,11 @@ static int __init con_init(void)
|
|||
mod_timer(&console_timer, jiffies + blankinterval);
|
||||
}
|
||||
|
||||
/*
|
||||
* kmalloc is not running yet - we use the bootmem allocator.
|
||||
*/
|
||||
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
|
||||
vc_cons[currcons].d = vc = alloc_bootmem(sizeof(struct vc_data));
|
||||
vc_cons[currcons].d = vc = kzalloc(sizeof(struct vc_data), GFP_NOWAIT);
|
||||
INIT_WORK(&vc_cons[currcons].SAK_work, vc_SAK);
|
||||
visual_init(vc, currcons, 1);
|
||||
vc->vc_screenbuf = (unsigned short *)alloc_bootmem(vc->vc_screenbuf_size);
|
||||
vc->vc_screenbuf = kzalloc(vc->vc_screenbuf_size, GFP_NOWAIT);
|
||||
vc->vc_kmalloced = 0;
|
||||
vc_init(vc, vc->vc_rows, vc->vc_cols,
|
||||
currcons || !vc->vc_sw->con_save_screen);
|
||||
|
|
|
|||
|
|
@ -3,3 +3,5 @@ obj-$(CONFIG_X86_CYCLONE_TIMER) += cyclone.o
|
|||
obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o
|
||||
obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o
|
||||
obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o
|
||||
obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o
|
||||
obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
@ -29,7 +28,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/sh_cmt.h>
|
||||
#include <linux/sh_timer.h>
|
||||
|
||||
struct sh_cmt_priv {
|
||||
void __iomem *mapbase;
|
||||
|
|
@ -47,6 +46,7 @@ struct sh_cmt_priv {
|
|||
unsigned long rate;
|
||||
spinlock_t lock;
|
||||
struct clock_event_device ced;
|
||||
struct clocksource cs;
|
||||
unsigned long total_cycles;
|
||||
};
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ static DEFINE_SPINLOCK(sh_cmt_lock);
|
|||
|
||||
static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
|
||||
{
|
||||
struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
void __iomem *base = p->mapbase;
|
||||
unsigned long offs;
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ static inline unsigned long sh_cmt_read(struct sh_cmt_priv *p, int reg_nr)
|
|||
static inline void sh_cmt_write(struct sh_cmt_priv *p, int reg_nr,
|
||||
unsigned long value)
|
||||
{
|
||||
struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
void __iomem *base = p->mapbase;
|
||||
unsigned long offs;
|
||||
|
||||
|
|
@ -110,23 +110,28 @@ static unsigned long sh_cmt_get_counter(struct sh_cmt_priv *p,
|
|||
int *has_wrapped)
|
||||
{
|
||||
unsigned long v1, v2, v3;
|
||||
int o1, o2;
|
||||
|
||||
o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
|
||||
|
||||
/* Make sure the timer value is stable. Stolen from acpi_pm.c */
|
||||
do {
|
||||
o2 = o1;
|
||||
v1 = sh_cmt_read(p, CMCNT);
|
||||
v2 = sh_cmt_read(p, CMCNT);
|
||||
v3 = sh_cmt_read(p, CMCNT);
|
||||
} while (unlikely((v1 > v2 && v1 < v3) || (v2 > v3 && v2 < v1)
|
||||
|| (v3 > v1 && v3 < v2)));
|
||||
o1 = sh_cmt_read(p, CMCSR) & p->overflow_bit;
|
||||
} while (unlikely((o1 != o2) || (v1 > v2 && v1 < v3)
|
||||
|| (v2 > v3 && v2 < v1) || (v3 > v1 && v3 < v2)));
|
||||
|
||||
*has_wrapped = sh_cmt_read(p, CMCSR) & p->overflow_bit;
|
||||
*has_wrapped = o1;
|
||||
return v2;
|
||||
}
|
||||
|
||||
|
||||
static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
|
||||
{
|
||||
struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
unsigned long flags, value;
|
||||
|
||||
/* start stop register shared by multiple timer channels */
|
||||
|
|
@ -144,7 +149,7 @@ static void sh_cmt_start_stop_ch(struct sh_cmt_priv *p, int start)
|
|||
|
||||
static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
|
||||
{
|
||||
struct sh_cmt_config *cfg = p->pdev->dev.platform_data;
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
/* enable clock */
|
||||
|
|
@ -153,16 +158,18 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
|
|||
pr_err("sh_cmt: cannot enable clock \"%s\"\n", cfg->clk);
|
||||
return ret;
|
||||
}
|
||||
*rate = clk_get_rate(p->clk) / 8;
|
||||
|
||||
/* make sure channel is disabled */
|
||||
sh_cmt_start_stop_ch(p, 0);
|
||||
|
||||
/* configure channel, periodic mode and maximum timeout */
|
||||
if (p->width == 16)
|
||||
sh_cmt_write(p, CMCSR, 0);
|
||||
else
|
||||
if (p->width == 16) {
|
||||
*rate = clk_get_rate(p->clk) / 512;
|
||||
sh_cmt_write(p, CMCSR, 0x43);
|
||||
} else {
|
||||
*rate = clk_get_rate(p->clk) / 8;
|
||||
sh_cmt_write(p, CMCSR, 0x01a4);
|
||||
}
|
||||
|
||||
sh_cmt_write(p, CMCOR, 0xffffffff);
|
||||
sh_cmt_write(p, CMCNT, 0);
|
||||
|
|
@ -376,6 +383,68 @@ static void sh_cmt_stop(struct sh_cmt_priv *p, unsigned long flag)
|
|||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
}
|
||||
|
||||
static struct sh_cmt_priv *cs_to_sh_cmt(struct clocksource *cs)
|
||||
{
|
||||
return container_of(cs, struct sh_cmt_priv, cs);
|
||||
}
|
||||
|
||||
static cycle_t sh_cmt_clocksource_read(struct clocksource *cs)
|
||||
{
|
||||
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
|
||||
unsigned long flags, raw;
|
||||
unsigned long value;
|
||||
int has_wrapped;
|
||||
|
||||
spin_lock_irqsave(&p->lock, flags);
|
||||
value = p->total_cycles;
|
||||
raw = sh_cmt_get_counter(p, &has_wrapped);
|
||||
|
||||
if (unlikely(has_wrapped))
|
||||
raw += p->match_value;
|
||||
spin_unlock_irqrestore(&p->lock, flags);
|
||||
|
||||
return value + raw;
|
||||
}
|
||||
|
||||
static int sh_cmt_clocksource_enable(struct clocksource *cs)
|
||||
{
|
||||
struct sh_cmt_priv *p = cs_to_sh_cmt(cs);
|
||||
int ret;
|
||||
|
||||
p->total_cycles = 0;
|
||||
|
||||
ret = sh_cmt_start(p, FLAG_CLOCKSOURCE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* TODO: calculate good shift from rate and counter bit width */
|
||||
cs->shift = 0;
|
||||
cs->mult = clocksource_hz2mult(p->rate, cs->shift);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_cmt_clocksource_disable(struct clocksource *cs)
|
||||
{
|
||||
sh_cmt_stop(cs_to_sh_cmt(cs), FLAG_CLOCKSOURCE);
|
||||
}
|
||||
|
||||
static int sh_cmt_register_clocksource(struct sh_cmt_priv *p,
|
||||
char *name, unsigned long rating)
|
||||
{
|
||||
struct clocksource *cs = &p->cs;
|
||||
|
||||
cs->name = name;
|
||||
cs->rating = rating;
|
||||
cs->read = sh_cmt_clocksource_read;
|
||||
cs->enable = sh_cmt_clocksource_enable;
|
||||
cs->disable = sh_cmt_clocksource_disable;
|
||||
cs->mask = CLOCKSOURCE_MASK(sizeof(unsigned long) * 8);
|
||||
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
|
||||
pr_info("sh_cmt: %s used as clock source\n", cs->name);
|
||||
clocksource_register(cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sh_cmt_priv *ced_to_sh_cmt(struct clock_event_device *ced)
|
||||
{
|
||||
return container_of(ced, struct sh_cmt_priv, ced);
|
||||
|
|
@ -468,9 +537,9 @@ static void sh_cmt_register_clockevent(struct sh_cmt_priv *p,
|
|||
clockevents_register_device(ced);
|
||||
}
|
||||
|
||||
int sh_cmt_register(struct sh_cmt_priv *p, char *name,
|
||||
unsigned long clockevent_rating,
|
||||
unsigned long clocksource_rating)
|
||||
static int sh_cmt_register(struct sh_cmt_priv *p, char *name,
|
||||
unsigned long clockevent_rating,
|
||||
unsigned long clocksource_rating)
|
||||
{
|
||||
if (p->width == (sizeof(p->max_match_value) * 8))
|
||||
p->max_match_value = ~0;
|
||||
|
|
@ -483,12 +552,15 @@ int sh_cmt_register(struct sh_cmt_priv *p, char *name,
|
|||
if (clockevent_rating)
|
||||
sh_cmt_register_clockevent(p, name, clockevent_rating);
|
||||
|
||||
if (clocksource_rating)
|
||||
sh_cmt_register_clocksource(p, name, clocksource_rating);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
|
||||
{
|
||||
struct sh_cmt_config *cfg = pdev->dev.platform_data;
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
ret = -ENXIO;
|
||||
|
|
@ -545,7 +617,7 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
|
|||
if (resource_size(res) == 6) {
|
||||
p->width = 16;
|
||||
p->overflow_bit = 0x80;
|
||||
p->clear_bits = ~0xc0;
|
||||
p->clear_bits = ~0x80;
|
||||
} else {
|
||||
p->width = 32;
|
||||
p->overflow_bit = 0x8000;
|
||||
|
|
@ -566,8 +638,14 @@ static int sh_cmt_setup(struct sh_cmt_priv *p, struct platform_device *pdev)
|
|||
static int __devinit sh_cmt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_cmt_priv *p = platform_get_drvdata(pdev);
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
if (p) {
|
||||
pr_info("sh_cmt: %s kept as earlytimer\n", cfg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
|
|
@ -577,7 +655,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
|
|||
ret = sh_cmt_setup(p, pdev);
|
||||
if (ret) {
|
||||
kfree(p);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
return ret;
|
||||
|
|
@ -606,6 +683,7 @@ static void __exit sh_cmt_exit(void)
|
|||
platform_driver_unregister(&sh_cmt_device_driver);
|
||||
}
|
||||
|
||||
early_platform_init("earlytimer", &sh_cmt_device_driver);
|
||||
module_init(sh_cmt_init);
|
||||
module_exit(sh_cmt_exit);
|
||||
|
||||
|
|
|
|||
357
drivers/clocksource/sh_mtu2.c
Normal file
357
drivers/clocksource/sh_mtu2.c
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
/*
|
||||
* SuperH Timer Support - MTU2
|
||||
*
|
||||
* Copyright (C) 2009 Magnus Damm
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/sh_timer.h>
|
||||
|
||||
struct sh_mtu2_priv {
|
||||
void __iomem *mapbase;
|
||||
struct clk *clk;
|
||||
struct irqaction irqaction;
|
||||
struct platform_device *pdev;
|
||||
unsigned long rate;
|
||||
unsigned long periodic;
|
||||
struct clock_event_device ced;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sh_mtu2_lock);
|
||||
|
||||
#define TSTR -1 /* shared register */
|
||||
#define TCR 0 /* channel register */
|
||||
#define TMDR 1 /* channel register */
|
||||
#define TIOR 2 /* channel register */
|
||||
#define TIER 3 /* channel register */
|
||||
#define TSR 4 /* channel register */
|
||||
#define TCNT 5 /* channel register */
|
||||
#define TGR 6 /* channel register */
|
||||
|
||||
static unsigned long mtu2_reg_offs[] = {
|
||||
[TCR] = 0,
|
||||
[TMDR] = 1,
|
||||
[TIOR] = 2,
|
||||
[TIER] = 4,
|
||||
[TSR] = 5,
|
||||
[TCNT] = 6,
|
||||
[TGR] = 8,
|
||||
};
|
||||
|
||||
static inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
void __iomem *base = p->mapbase;
|
||||
unsigned long offs;
|
||||
|
||||
if (reg_nr == TSTR)
|
||||
return ioread8(base + cfg->channel_offset);
|
||||
|
||||
offs = mtu2_reg_offs[reg_nr];
|
||||
|
||||
if ((reg_nr == TCNT) || (reg_nr == TGR))
|
||||
return ioread16(base + offs);
|
||||
else
|
||||
return ioread8(base + offs);
|
||||
}
|
||||
|
||||
static inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr,
|
||||
unsigned long value)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
void __iomem *base = p->mapbase;
|
||||
unsigned long offs;
|
||||
|
||||
if (reg_nr == TSTR) {
|
||||
iowrite8(value, base + cfg->channel_offset);
|
||||
return;
|
||||
}
|
||||
|
||||
offs = mtu2_reg_offs[reg_nr];
|
||||
|
||||
if ((reg_nr == TCNT) || (reg_nr == TGR))
|
||||
iowrite16(value, base + offs);
|
||||
else
|
||||
iowrite8(value, base + offs);
|
||||
}
|
||||
|
||||
static void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
unsigned long flags, value;
|
||||
|
||||
/* start stop register shared by multiple timer channels */
|
||||
spin_lock_irqsave(&sh_mtu2_lock, flags);
|
||||
value = sh_mtu2_read(p, TSTR);
|
||||
|
||||
if (start)
|
||||
value |= 1 << cfg->timer_bit;
|
||||
else
|
||||
value &= ~(1 << cfg->timer_bit);
|
||||
|
||||
sh_mtu2_write(p, TSTR, value);
|
||||
spin_unlock_irqrestore(&sh_mtu2_lock, flags);
|
||||
}
|
||||
|
||||
static int sh_mtu2_enable(struct sh_mtu2_priv *p)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
/* enable clock */
|
||||
ret = clk_enable(p->clk);
|
||||
if (ret) {
|
||||
pr_err("sh_mtu2: cannot enable clock \"%s\"\n", cfg->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure channel is disabled */
|
||||
sh_mtu2_start_stop_ch(p, 0);
|
||||
|
||||
p->rate = clk_get_rate(p->clk) / 64;
|
||||
p->periodic = (p->rate + HZ/2) / HZ;
|
||||
|
||||
/* "Periodic Counter Operation" */
|
||||
sh_mtu2_write(p, TCR, 0x23); /* TGRA clear, divide clock by 64 */
|
||||
sh_mtu2_write(p, TIOR, 0);
|
||||
sh_mtu2_write(p, TGR, p->periodic);
|
||||
sh_mtu2_write(p, TCNT, 0);
|
||||
sh_mtu2_write(p, TMDR, 0);
|
||||
sh_mtu2_write(p, TIER, 0x01);
|
||||
|
||||
/* enable channel */
|
||||
sh_mtu2_start_stop_ch(p, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_mtu2_disable(struct sh_mtu2_priv *p)
|
||||
{
|
||||
/* disable channel */
|
||||
sh_mtu2_start_stop_ch(p, 0);
|
||||
|
||||
/* stop clock */
|
||||
clk_disable(p->clk);
|
||||
}
|
||||
|
||||
static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct sh_mtu2_priv *p = dev_id;
|
||||
|
||||
/* acknowledge interrupt */
|
||||
sh_mtu2_read(p, TSR);
|
||||
sh_mtu2_write(p, TSR, 0xfe);
|
||||
|
||||
/* notify clockevent layer */
|
||||
p->ced.event_handler(&p->ced);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct sh_mtu2_priv *ced_to_sh_mtu2(struct clock_event_device *ced)
|
||||
{
|
||||
return container_of(ced, struct sh_mtu2_priv, ced);
|
||||
}
|
||||
|
||||
static void sh_mtu2_clock_event_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *ced)
|
||||
{
|
||||
struct sh_mtu2_priv *p = ced_to_sh_mtu2(ced);
|
||||
int disabled = 0;
|
||||
|
||||
/* deal with old setting first */
|
||||
switch (ced->mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
sh_mtu2_disable(p);
|
||||
disabled = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
pr_info("sh_mtu2: %s used for periodic clock events\n",
|
||||
ced->name);
|
||||
sh_mtu2_enable(p);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
if (!disabled)
|
||||
sh_mtu2_disable(p);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p,
|
||||
char *name, unsigned long rating)
|
||||
{
|
||||
struct clock_event_device *ced = &p->ced;
|
||||
int ret;
|
||||
|
||||
memset(ced, 0, sizeof(*ced));
|
||||
|
||||
ced->name = name;
|
||||
ced->features = CLOCK_EVT_FEAT_PERIODIC;
|
||||
ced->rating = rating;
|
||||
ced->cpumask = cpumask_of(0);
|
||||
ced->set_mode = sh_mtu2_clock_event_mode;
|
||||
|
||||
ret = setup_irq(p->irqaction.irq, &p->irqaction);
|
||||
if (ret) {
|
||||
pr_err("sh_mtu2: failed to request irq %d\n",
|
||||
p->irqaction.irq);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("sh_mtu2: %s used for clock events\n", ced->name);
|
||||
clockevents_register_device(ced);
|
||||
}
|
||||
|
||||
static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name,
|
||||
unsigned long clockevent_rating)
|
||||
{
|
||||
if (clockevent_rating)
|
||||
sh_mtu2_register_clockevent(p, name, clockevent_rating);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev)
|
||||
{
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
ret = -ENXIO;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pdev = pdev;
|
||||
|
||||
if (!cfg) {
|
||||
dev_err(&p->pdev->dev, "missing platform data\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, p);
|
||||
|
||||
res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&p->pdev->dev, "failed to get I/O memory\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(p->pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&p->pdev->dev, "failed to get irq\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* map memory, let mapbase point to our channel */
|
||||
p->mapbase = ioremap_nocache(res->start, resource_size(res));
|
||||
if (p->mapbase == NULL) {
|
||||
pr_err("sh_mtu2: failed to remap I/O memory\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* setup data for setup_irq() (too early for request_irq()) */
|
||||
p->irqaction.name = cfg->name;
|
||||
p->irqaction.handler = sh_mtu2_interrupt;
|
||||
p->irqaction.dev_id = p;
|
||||
p->irqaction.irq = irq;
|
||||
p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
|
||||
p->irqaction.mask = CPU_MASK_NONE;
|
||||
|
||||
/* get hold of clock */
|
||||
p->clk = clk_get(&p->pdev->dev, cfg->clk);
|
||||
if (IS_ERR(p->clk)) {
|
||||
pr_err("sh_mtu2: cannot get clock \"%s\"\n", cfg->clk);
|
||||
ret = PTR_ERR(p->clk);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return sh_mtu2_register(p, cfg->name, cfg->clockevent_rating);
|
||||
err1:
|
||||
iounmap(p->mapbase);
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit sh_mtu2_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_mtu2_priv *p = platform_get_drvdata(pdev);
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
if (p) {
|
||||
pr_info("sh_mtu2: %s kept as earlytimer\n", cfg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sh_mtu2_setup(p, pdev);
|
||||
if (ret) {
|
||||
kfree(p);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit sh_mtu2_remove(struct platform_device *pdev)
|
||||
{
|
||||
return -EBUSY; /* cannot unregister clockevent */
|
||||
}
|
||||
|
||||
static struct platform_driver sh_mtu2_device_driver = {
|
||||
.probe = sh_mtu2_probe,
|
||||
.remove = __devexit_p(sh_mtu2_remove),
|
||||
.driver = {
|
||||
.name = "sh_mtu2",
|
||||
}
|
||||
};
|
||||
|
||||
static int __init sh_mtu2_init(void)
|
||||
{
|
||||
return platform_driver_register(&sh_mtu2_device_driver);
|
||||
}
|
||||
|
||||
static void __exit sh_mtu2_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sh_mtu2_device_driver);
|
||||
}
|
||||
|
||||
early_platform_init("earlytimer", &sh_mtu2_device_driver);
|
||||
module_init(sh_mtu2_init);
|
||||
module_exit(sh_mtu2_exit);
|
||||
|
||||
MODULE_AUTHOR("Magnus Damm");
|
||||
MODULE_DESCRIPTION("SuperH MTU2 Timer Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
461
drivers/clocksource/sh_tmu.c
Normal file
461
drivers/clocksource/sh_tmu.c
Normal file
|
|
@ -0,0 +1,461 @@
|
|||
/*
|
||||
* SuperH Timer Support - TMU
|
||||
*
|
||||
* Copyright (C) 2009 Magnus Damm
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/sh_timer.h>
|
||||
|
||||
struct sh_tmu_priv {
|
||||
void __iomem *mapbase;
|
||||
struct clk *clk;
|
||||
struct irqaction irqaction;
|
||||
struct platform_device *pdev;
|
||||
unsigned long rate;
|
||||
unsigned long periodic;
|
||||
struct clock_event_device ced;
|
||||
struct clocksource cs;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(sh_tmu_lock);
|
||||
|
||||
#define TSTR -1 /* shared register */
|
||||
#define TCOR 0 /* channel register */
|
||||
#define TCNT 1 /* channel register */
|
||||
#define TCR 2 /* channel register */
|
||||
|
||||
static inline unsigned long sh_tmu_read(struct sh_tmu_priv *p, int reg_nr)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
void __iomem *base = p->mapbase;
|
||||
unsigned long offs;
|
||||
|
||||
if (reg_nr == TSTR)
|
||||
return ioread8(base - cfg->channel_offset);
|
||||
|
||||
offs = reg_nr << 2;
|
||||
|
||||
if (reg_nr == TCR)
|
||||
return ioread16(base + offs);
|
||||
else
|
||||
return ioread32(base + offs);
|
||||
}
|
||||
|
||||
static inline void sh_tmu_write(struct sh_tmu_priv *p, int reg_nr,
|
||||
unsigned long value)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
void __iomem *base = p->mapbase;
|
||||
unsigned long offs;
|
||||
|
||||
if (reg_nr == TSTR) {
|
||||
iowrite8(value, base - cfg->channel_offset);
|
||||
return;
|
||||
}
|
||||
|
||||
offs = reg_nr << 2;
|
||||
|
||||
if (reg_nr == TCR)
|
||||
iowrite16(value, base + offs);
|
||||
else
|
||||
iowrite32(value, base + offs);
|
||||
}
|
||||
|
||||
static void sh_tmu_start_stop_ch(struct sh_tmu_priv *p, int start)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
unsigned long flags, value;
|
||||
|
||||
/* start stop register shared by multiple timer channels */
|
||||
spin_lock_irqsave(&sh_tmu_lock, flags);
|
||||
value = sh_tmu_read(p, TSTR);
|
||||
|
||||
if (start)
|
||||
value |= 1 << cfg->timer_bit;
|
||||
else
|
||||
value &= ~(1 << cfg->timer_bit);
|
||||
|
||||
sh_tmu_write(p, TSTR, value);
|
||||
spin_unlock_irqrestore(&sh_tmu_lock, flags);
|
||||
}
|
||||
|
||||
static int sh_tmu_enable(struct sh_tmu_priv *p)
|
||||
{
|
||||
struct sh_timer_config *cfg = p->pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
/* enable clock */
|
||||
ret = clk_enable(p->clk);
|
||||
if (ret) {
|
||||
pr_err("sh_tmu: cannot enable clock \"%s\"\n", cfg->clk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* make sure channel is disabled */
|
||||
sh_tmu_start_stop_ch(p, 0);
|
||||
|
||||
/* maximum timeout */
|
||||
sh_tmu_write(p, TCOR, 0xffffffff);
|
||||
sh_tmu_write(p, TCNT, 0xffffffff);
|
||||
|
||||
/* configure channel to parent clock / 4, irq off */
|
||||
p->rate = clk_get_rate(p->clk) / 4;
|
||||
sh_tmu_write(p, TCR, 0x0000);
|
||||
|
||||
/* enable channel */
|
||||
sh_tmu_start_stop_ch(p, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_tmu_disable(struct sh_tmu_priv *p)
|
||||
{
|
||||
/* disable channel */
|
||||
sh_tmu_start_stop_ch(p, 0);
|
||||
|
||||
/* stop clock */
|
||||
clk_disable(p->clk);
|
||||
}
|
||||
|
||||
static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
|
||||
int periodic)
|
||||
{
|
||||
/* stop timer */
|
||||
sh_tmu_start_stop_ch(p, 0);
|
||||
|
||||
/* acknowledge interrupt */
|
||||
sh_tmu_read(p, TCR);
|
||||
|
||||
/* enable interrupt */
|
||||
sh_tmu_write(p, TCR, 0x0020);
|
||||
|
||||
/* reload delta value in case of periodic timer */
|
||||
if (periodic)
|
||||
sh_tmu_write(p, TCOR, delta);
|
||||
else
|
||||
sh_tmu_write(p, TCOR, 0);
|
||||
|
||||
sh_tmu_write(p, TCNT, delta);
|
||||
|
||||
/* start timer */
|
||||
sh_tmu_start_stop_ch(p, 1);
|
||||
}
|
||||
|
||||
static irqreturn_t sh_tmu_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct sh_tmu_priv *p = dev_id;
|
||||
|
||||
/* disable or acknowledge interrupt */
|
||||
if (p->ced.mode == CLOCK_EVT_MODE_ONESHOT)
|
||||
sh_tmu_write(p, TCR, 0x0000);
|
||||
else
|
||||
sh_tmu_write(p, TCR, 0x0020);
|
||||
|
||||
/* notify clockevent layer */
|
||||
p->ced.event_handler(&p->ced);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct sh_tmu_priv *cs_to_sh_tmu(struct clocksource *cs)
|
||||
{
|
||||
return container_of(cs, struct sh_tmu_priv, cs);
|
||||
}
|
||||
|
||||
static cycle_t sh_tmu_clocksource_read(struct clocksource *cs)
|
||||
{
|
||||
struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
|
||||
|
||||
return sh_tmu_read(p, TCNT) ^ 0xffffffff;
|
||||
}
|
||||
|
||||
static int sh_tmu_clocksource_enable(struct clocksource *cs)
|
||||
{
|
||||
struct sh_tmu_priv *p = cs_to_sh_tmu(cs);
|
||||
int ret;
|
||||
|
||||
ret = sh_tmu_enable(p);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* TODO: calculate good shift from rate and counter bit width */
|
||||
cs->shift = 10;
|
||||
cs->mult = clocksource_hz2mult(p->rate, cs->shift);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_tmu_clocksource_disable(struct clocksource *cs)
|
||||
{
|
||||
sh_tmu_disable(cs_to_sh_tmu(cs));
|
||||
}
|
||||
|
||||
static int sh_tmu_register_clocksource(struct sh_tmu_priv *p,
|
||||
char *name, unsigned long rating)
|
||||
{
|
||||
struct clocksource *cs = &p->cs;
|
||||
|
||||
cs->name = name;
|
||||
cs->rating = rating;
|
||||
cs->read = sh_tmu_clocksource_read;
|
||||
cs->enable = sh_tmu_clocksource_enable;
|
||||
cs->disable = sh_tmu_clocksource_disable;
|
||||
cs->mask = CLOCKSOURCE_MASK(32);
|
||||
cs->flags = CLOCK_SOURCE_IS_CONTINUOUS;
|
||||
pr_info("sh_tmu: %s used as clock source\n", cs->name);
|
||||
clocksource_register(cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sh_tmu_priv *ced_to_sh_tmu(struct clock_event_device *ced)
|
||||
{
|
||||
return container_of(ced, struct sh_tmu_priv, ced);
|
||||
}
|
||||
|
||||
static void sh_tmu_clock_event_start(struct sh_tmu_priv *p, int periodic)
|
||||
{
|
||||
struct clock_event_device *ced = &p->ced;
|
||||
|
||||
sh_tmu_enable(p);
|
||||
|
||||
/* TODO: calculate good shift from rate and counter bit width */
|
||||
|
||||
ced->shift = 32;
|
||||
ced->mult = div_sc(p->rate, NSEC_PER_SEC, ced->shift);
|
||||
ced->max_delta_ns = clockevent_delta2ns(0xffffffff, ced);
|
||||
ced->min_delta_ns = 5000;
|
||||
|
||||
if (periodic) {
|
||||
p->periodic = (p->rate + HZ/2) / HZ;
|
||||
sh_tmu_set_next(p, p->periodic, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void sh_tmu_clock_event_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *ced)
|
||||
{
|
||||
struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
|
||||
int disabled = 0;
|
||||
|
||||
/* deal with old setting first */
|
||||
switch (ced->mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
sh_tmu_disable(p);
|
||||
disabled = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_PERIODIC:
|
||||
pr_info("sh_tmu: %s used for periodic clock events\n",
|
||||
ced->name);
|
||||
sh_tmu_clock_event_start(p, 1);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
pr_info("sh_tmu: %s used for oneshot clock events\n",
|
||||
ced->name);
|
||||
sh_tmu_clock_event_start(p, 0);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
if (!disabled)
|
||||
sh_tmu_disable(p);
|
||||
break;
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int sh_tmu_clock_event_next(unsigned long delta,
|
||||
struct clock_event_device *ced)
|
||||
{
|
||||
struct sh_tmu_priv *p = ced_to_sh_tmu(ced);
|
||||
|
||||
BUG_ON(ced->mode != CLOCK_EVT_MODE_ONESHOT);
|
||||
|
||||
/* program new delta value */
|
||||
sh_tmu_set_next(p, delta, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sh_tmu_register_clockevent(struct sh_tmu_priv *p,
|
||||
char *name, unsigned long rating)
|
||||
{
|
||||
struct clock_event_device *ced = &p->ced;
|
||||
int ret;
|
||||
|
||||
memset(ced, 0, sizeof(*ced));
|
||||
|
||||
ced->name = name;
|
||||
ced->features = CLOCK_EVT_FEAT_PERIODIC;
|
||||
ced->features |= CLOCK_EVT_FEAT_ONESHOT;
|
||||
ced->rating = rating;
|
||||
ced->cpumask = cpumask_of(0);
|
||||
ced->set_next_event = sh_tmu_clock_event_next;
|
||||
ced->set_mode = sh_tmu_clock_event_mode;
|
||||
|
||||
ret = setup_irq(p->irqaction.irq, &p->irqaction);
|
||||
if (ret) {
|
||||
pr_err("sh_tmu: failed to request irq %d\n",
|
||||
p->irqaction.irq);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("sh_tmu: %s used for clock events\n", ced->name);
|
||||
clockevents_register_device(ced);
|
||||
}
|
||||
|
||||
static int sh_tmu_register(struct sh_tmu_priv *p, char *name,
|
||||
unsigned long clockevent_rating,
|
||||
unsigned long clocksource_rating)
|
||||
{
|
||||
if (clockevent_rating)
|
||||
sh_tmu_register_clockevent(p, name, clockevent_rating);
|
||||
else if (clocksource_rating)
|
||||
sh_tmu_register_clocksource(p, name, clocksource_rating);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_tmu_setup(struct sh_tmu_priv *p, struct platform_device *pdev)
|
||||
{
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
struct resource *res;
|
||||
int irq, ret;
|
||||
ret = -ENXIO;
|
||||
|
||||
memset(p, 0, sizeof(*p));
|
||||
p->pdev = pdev;
|
||||
|
||||
if (!cfg) {
|
||||
dev_err(&p->pdev->dev, "missing platform data\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
platform_set_drvdata(pdev, p);
|
||||
|
||||
res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&p->pdev->dev, "failed to get I/O memory\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
irq = platform_get_irq(p->pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(&p->pdev->dev, "failed to get irq\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* map memory, let mapbase point to our channel */
|
||||
p->mapbase = ioremap_nocache(res->start, resource_size(res));
|
||||
if (p->mapbase == NULL) {
|
||||
pr_err("sh_tmu: failed to remap I/O memory\n");
|
||||
goto err0;
|
||||
}
|
||||
|
||||
/* setup data for setup_irq() (too early for request_irq()) */
|
||||
p->irqaction.name = cfg->name;
|
||||
p->irqaction.handler = sh_tmu_interrupt;
|
||||
p->irqaction.dev_id = p;
|
||||
p->irqaction.irq = irq;
|
||||
p->irqaction.flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL;
|
||||
p->irqaction.mask = CPU_MASK_NONE;
|
||||
|
||||
/* get hold of clock */
|
||||
p->clk = clk_get(&p->pdev->dev, cfg->clk);
|
||||
if (IS_ERR(p->clk)) {
|
||||
pr_err("sh_tmu: cannot get clock \"%s\"\n", cfg->clk);
|
||||
ret = PTR_ERR(p->clk);
|
||||
goto err1;
|
||||
}
|
||||
|
||||
return sh_tmu_register(p, cfg->name,
|
||||
cfg->clockevent_rating,
|
||||
cfg->clocksource_rating);
|
||||
err1:
|
||||
iounmap(p->mapbase);
|
||||
err0:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devinit sh_tmu_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct sh_tmu_priv *p = platform_get_drvdata(pdev);
|
||||
struct sh_timer_config *cfg = pdev->dev.platform_data;
|
||||
int ret;
|
||||
|
||||
if (p) {
|
||||
pr_info("sh_tmu: %s kept as earlytimer\n", cfg->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p = kmalloc(sizeof(*p), GFP_KERNEL);
|
||||
if (p == NULL) {
|
||||
dev_err(&pdev->dev, "failed to allocate driver data\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = sh_tmu_setup(p, pdev);
|
||||
if (ret) {
|
||||
kfree(p);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit sh_tmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
return -EBUSY; /* cannot unregister clockevent and clocksource */
|
||||
}
|
||||
|
||||
static struct platform_driver sh_tmu_device_driver = {
|
||||
.probe = sh_tmu_probe,
|
||||
.remove = __devexit_p(sh_tmu_remove),
|
||||
.driver = {
|
||||
.name = "sh_tmu",
|
||||
}
|
||||
};
|
||||
|
||||
static int __init sh_tmu_init(void)
|
||||
{
|
||||
return platform_driver_register(&sh_tmu_device_driver);
|
||||
}
|
||||
|
||||
static void __exit sh_tmu_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&sh_tmu_device_driver);
|
||||
}
|
||||
|
||||
early_platform_init("earlytimer", &sh_tmu_device_driver);
|
||||
module_init(sh_tmu_init);
|
||||
module_exit(sh_tmu_exit);
|
||||
|
||||
MODULE_AUTHOR("Magnus Damm");
|
||||
MODULE_DESCRIPTION("SuperH TMU Timer Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
|
@ -808,7 +808,7 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
|
|||
ret = -ENOMEM;
|
||||
goto nomem_out;
|
||||
}
|
||||
if (!alloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
|
||||
if (!zalloc_cpumask_var(&policy->related_cpus, GFP_KERNEL)) {
|
||||
free_cpumask_var(policy->cpus);
|
||||
kfree(policy);
|
||||
ret = -ENOMEM;
|
||||
|
|
@ -1070,11 +1070,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev)
|
|||
spin_unlock_irqrestore(&cpufreq_driver_lock, flags);
|
||||
#endif
|
||||
|
||||
unlock_policy_rwsem_write(cpu);
|
||||
|
||||
if (cpufreq_driver->target)
|
||||
__cpufreq_governor(data, CPUFREQ_GOV_STOP);
|
||||
|
||||
unlock_policy_rwsem_write(cpu);
|
||||
|
||||
kobject_put(&data->kobj);
|
||||
|
||||
/* we need to make sure that the underlying kobj is actually
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
|
|||
* (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then
|
||||
* cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
|
||||
* is recursive for the same process. -Venki
|
||||
* DEADLOCK ALERT! (2) : do_dbs_timer() must not take the dbs_mutex, because it
|
||||
* would deadlock with cancel_delayed_work_sync(), which is needed for proper
|
||||
* raceless workqueue teardown.
|
||||
*/
|
||||
static DEFINE_MUTEX(dbs_mutex);
|
||||
|
||||
|
|
@ -542,7 +545,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
|
|||
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
|
||||
{
|
||||
dbs_info->enable = 0;
|
||||
cancel_delayed_work(&dbs_info->work);
|
||||
cancel_delayed_work_sync(&dbs_info->work);
|
||||
}
|
||||
|
||||
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
|
|
|
|||
|
|
@ -98,6 +98,9 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */
|
|||
* (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then
|
||||
* cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock
|
||||
* is recursive for the same process. -Venki
|
||||
* DEADLOCK ALERT! (2) : do_dbs_timer() must not take the dbs_mutex, because it
|
||||
* would deadlock with cancel_delayed_work_sync(), which is needed for proper
|
||||
* raceless workqueue teardown.
|
||||
*/
|
||||
static DEFINE_MUTEX(dbs_mutex);
|
||||
|
||||
|
|
@ -562,7 +565,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info)
|
|||
static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info)
|
||||
{
|
||||
dbs_info->enable = 0;
|
||||
cancel_delayed_work(&dbs_info->work);
|
||||
cancel_delayed_work_sync(&dbs_info->work);
|
||||
}
|
||||
|
||||
static int cpufreq_governor_dbs(struct cpufreq_policy *policy,
|
||||
|
|
|
|||
|
|
@ -179,9 +179,14 @@ static void dma_halt(struct fsl_dma_chan *fsl_chan)
|
|||
static void set_ld_eol(struct fsl_dma_chan *fsl_chan,
|
||||
struct fsl_desc_sw *desc)
|
||||
{
|
||||
u64 snoop_bits;
|
||||
|
||||
snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
|
||||
? FSL_DMA_SNEN : 0;
|
||||
|
||||
desc->hw.next_ln_addr = CPU_TO_DMA(fsl_chan,
|
||||
DMA_TO_CPU(fsl_chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL,
|
||||
64);
|
||||
DMA_TO_CPU(fsl_chan, desc->hw.next_ln_addr, 64) | FSL_DMA_EOL
|
||||
| snoop_bits, 64);
|
||||
}
|
||||
|
||||
static void append_ld_queue(struct fsl_dma_chan *fsl_chan,
|
||||
|
|
@ -313,8 +318,8 @@ static void fsl_chan_toggle_ext_start(struct fsl_dma_chan *fsl_chan, int enable)
|
|||
|
||||
static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
{
|
||||
struct fsl_desc_sw *desc = tx_to_fsl_desc(tx);
|
||||
struct fsl_dma_chan *fsl_chan = to_fsl_chan(tx->chan);
|
||||
struct fsl_desc_sw *desc;
|
||||
unsigned long flags;
|
||||
dma_cookie_t cookie;
|
||||
|
||||
|
|
@ -322,14 +327,17 @@ static dma_cookie_t fsl_dma_tx_submit(struct dma_async_tx_descriptor *tx)
|
|||
spin_lock_irqsave(&fsl_chan->desc_lock, flags);
|
||||
|
||||
cookie = fsl_chan->common.cookie;
|
||||
cookie++;
|
||||
if (cookie < 0)
|
||||
cookie = 1;
|
||||
desc->async_tx.cookie = cookie;
|
||||
fsl_chan->common.cookie = desc->async_tx.cookie;
|
||||
list_for_each_entry(desc, &tx->tx_list, node) {
|
||||
cookie++;
|
||||
if (cookie < 0)
|
||||
cookie = 1;
|
||||
|
||||
append_ld_queue(fsl_chan, desc);
|
||||
list_splice_init(&desc->async_tx.tx_list, fsl_chan->ld_queue.prev);
|
||||
desc->async_tx.cookie = cookie;
|
||||
}
|
||||
|
||||
fsl_chan->common.cookie = cookie;
|
||||
append_ld_queue(fsl_chan, tx_to_fsl_desc(tx));
|
||||
list_splice_init(&tx->tx_list, fsl_chan->ld_queue.prev);
|
||||
|
||||
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
|
||||
|
||||
|
|
@ -454,8 +462,8 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
|
|||
{
|
||||
struct fsl_dma_chan *fsl_chan;
|
||||
struct fsl_desc_sw *first = NULL, *prev = NULL, *new;
|
||||
struct list_head *list;
|
||||
size_t copy;
|
||||
LIST_HEAD(link_chain);
|
||||
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
|
@ -472,7 +480,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
|
|||
if (!new) {
|
||||
dev_err(fsl_chan->dev,
|
||||
"No free memory for link descriptor\n");
|
||||
return NULL;
|
||||
goto fail;
|
||||
}
|
||||
#ifdef FSL_DMA_LD_DEBUG
|
||||
dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
|
||||
|
|
@ -507,7 +515,19 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
|
|||
/* Set End-of-link to the last link descriptor of new list*/
|
||||
set_ld_eol(fsl_chan, new);
|
||||
|
||||
return first ? &first->async_tx : NULL;
|
||||
return &first->async_tx;
|
||||
|
||||
fail:
|
||||
if (!first)
|
||||
return NULL;
|
||||
|
||||
list = &first->async_tx.tx_list;
|
||||
list_for_each_entry_safe_reverse(new, prev, list, node) {
|
||||
list_del(&new->node);
|
||||
dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -598,15 +618,16 @@ static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan)
|
|||
dma_addr_t next_dest_addr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fsl_chan->desc_lock, flags);
|
||||
|
||||
if (!dma_is_idle(fsl_chan))
|
||||
return;
|
||||
goto out_unlock;
|
||||
|
||||
dma_halt(fsl_chan);
|
||||
|
||||
/* If there are some link descriptors
|
||||
* not transfered in queue. We need to start it.
|
||||
*/
|
||||
spin_lock_irqsave(&fsl_chan->desc_lock, flags);
|
||||
|
||||
/* Find the first un-transfer desciptor */
|
||||
for (ld_node = fsl_chan->ld_queue.next;
|
||||
|
|
@ -617,19 +638,20 @@ static void fsl_chan_xfer_ld_queue(struct fsl_dma_chan *fsl_chan)
|
|||
fsl_chan->common.cookie) == DMA_SUCCESS);
|
||||
ld_node = ld_node->next);
|
||||
|
||||
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
|
||||
|
||||
if (ld_node != &fsl_chan->ld_queue) {
|
||||
/* Get the ld start address from ld_queue */
|
||||
next_dest_addr = to_fsl_desc(ld_node)->async_tx.phys;
|
||||
dev_dbg(fsl_chan->dev, "xfer LDs staring from %p\n",
|
||||
(void *)next_dest_addr);
|
||||
dev_dbg(fsl_chan->dev, "xfer LDs staring from 0x%llx\n",
|
||||
(unsigned long long)next_dest_addr);
|
||||
set_cdar(fsl_chan, next_dest_addr);
|
||||
dma_start(fsl_chan);
|
||||
} else {
|
||||
set_cdar(fsl_chan, 0);
|
||||
set_ndar(fsl_chan, 0);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
spin_unlock_irqrestore(&fsl_chan->desc_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -734,8 +756,9 @@ static irqreturn_t fsl_dma_chan_do_interrupt(int irq, void *data)
|
|||
*/
|
||||
if (stat & FSL_DMA_SR_EOSI) {
|
||||
dev_dbg(fsl_chan->dev, "event: End-of-segments INT\n");
|
||||
dev_dbg(fsl_chan->dev, "event: clndar %p, nlndar %p\n",
|
||||
(void *)get_cdar(fsl_chan), (void *)get_ndar(fsl_chan));
|
||||
dev_dbg(fsl_chan->dev, "event: clndar 0x%llx, nlndar 0x%llx\n",
|
||||
(unsigned long long)get_cdar(fsl_chan),
|
||||
(unsigned long long)get_ndar(fsl_chan));
|
||||
stat &= ~FSL_DMA_SR_EOSI;
|
||||
update_cookie = 1;
|
||||
}
|
||||
|
|
@ -830,7 +853,7 @@ static int __devinit fsl_dma_chan_probe(struct fsl_dma_device *fdev,
|
|||
new_fsl_chan->reg.end - new_fsl_chan->reg.start + 1);
|
||||
|
||||
new_fsl_chan->id = ((new_fsl_chan->reg.start - 0x100) & 0xfff) >> 7;
|
||||
if (new_fsl_chan->id > FSL_DMA_MAX_CHANS_PER_DEVICE) {
|
||||
if (new_fsl_chan->id >= FSL_DMA_MAX_CHANS_PER_DEVICE) {
|
||||
dev_err(fdev->dev, "There is no %d channel!\n",
|
||||
new_fsl_chan->id);
|
||||
err = -EINVAL;
|
||||
|
|
@ -925,8 +948,8 @@ static int __devinit of_fsl_dma_probe(struct of_device *dev,
|
|||
}
|
||||
|
||||
dev_info(&dev->dev, "Probe the Freescale DMA driver for %s "
|
||||
"controller at %p...\n",
|
||||
match->compatible, (void *)fdev->reg.start);
|
||||
"controller at 0x%llx...\n",
|
||||
match->compatible, (unsigned long long)fdev->reg.start);
|
||||
fdev->reg_base = ioremap(fdev->reg.start, fdev->reg.end
|
||||
- fdev->reg.start + 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
|
|||
xfercap = (xfercap_scale == 0 ? -1 : (1UL << xfercap_scale));
|
||||
|
||||
#ifdef CONFIG_I7300_IDLE_IOAT_CHANNEL
|
||||
if (i7300_idle_platform_probe(NULL, NULL) == 0) {
|
||||
if (i7300_idle_platform_probe(NULL, NULL, 1) == 0) {
|
||||
device->common.chancnt--;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue