mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 02:32:09 -04:00
Merge branch 'master' of /home/davem/src/GIT/linux-2.6/
This commit is contained in:
commit
0702b30dd8
1194 changed files with 48041 additions and 34409 deletions
|
|
@ -254,13 +254,6 @@ config ACPI_PCI_SLOT
|
|||
help you correlate PCI bus addresses with the physical geography
|
||||
of your slots. If you are unsure, say N.
|
||||
|
||||
config ACPI_SYSTEM
|
||||
bool
|
||||
default y
|
||||
help
|
||||
This driver will enable your system to shut down using ACPI, and
|
||||
dump your ACPI DSDT table using /proc/acpi/dsdt.
|
||||
|
||||
config X86_PM_TIMER
|
||||
bool "Power Management Timer Support" if EMBEDDED
|
||||
depends on X86
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
|
|||
obj-$(CONFIG_ACPI_CONTAINER) += container.o
|
||||
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
|
||||
obj-y += power.o
|
||||
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
|
||||
obj-y += system.o event.o
|
||||
obj-$(CONFIG_ACPI_DEBUG) += debug.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += numa.o
|
||||
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
|
||||
|
|
|
|||
|
|
@ -138,6 +138,29 @@ static int acpi_battery_technology(struct acpi_battery *battery)
|
|||
|
||||
static int acpi_battery_get_state(struct acpi_battery *battery);
|
||||
|
||||
static int acpi_battery_is_charged(struct acpi_battery *battery)
|
||||
{
|
||||
/* either charging or discharging */
|
||||
if (battery->state != 0)
|
||||
return 0;
|
||||
|
||||
/* battery not reporting charge */
|
||||
if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
|
||||
battery->capacity_now == 0)
|
||||
return 0;
|
||||
|
||||
/* good batteries update full_charge as the batteries degrade */
|
||||
if (battery->full_charge_capacity == battery->capacity_now)
|
||||
return 1;
|
||||
|
||||
/* fallback to using design values for broken batteries */
|
||||
if (battery->design_capacity == battery->capacity_now)
|
||||
return 1;
|
||||
|
||||
/* we don't do any sort of metric based on percentages */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_battery_get_property(struct power_supply *psy,
|
||||
enum power_supply_property psp,
|
||||
union power_supply_propval *val)
|
||||
|
|
@ -155,7 +178,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
|
|||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||||
else if (battery->state & 0x02)
|
||||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||||
else if (battery->state == 0)
|
||||
else if (acpi_battery_is_charged(battery))
|
||||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||||
else
|
||||
val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
|
||||
|
|
|
|||
|
|
@ -758,8 +758,7 @@ static int __init acpi_bus_init(void)
|
|||
acpi_status status = AE_OK;
|
||||
extern acpi_status acpi_os_initialize1(void);
|
||||
|
||||
|
||||
status = acpi_os_initialize1();
|
||||
acpi_os_initialize1();
|
||||
|
||||
status =
|
||||
acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
|
||||
|
|
@ -769,12 +768,6 @@ static int __init acpi_bus_init(void)
|
|||
goto error1;
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Unable to initialize ACPI OS objects\n");
|
||||
goto error1;
|
||||
}
|
||||
|
||||
/*
|
||||
* ACPI 2.0 requires the EC driver to be loaded and work before
|
||||
* the EC device is found in the namespace (i.e. before acpi_initialize_objects()
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ static struct acpi_ec {
|
|||
spinlock_t curr_lock;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Transaction Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
|
@ -259,6 +261,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
|
|||
clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
|
||||
acpi_disable_gpe(NULL, ec->gpe);
|
||||
}
|
||||
if (EC_FLAGS_MSI)
|
||||
udelay(ACPI_EC_DELAY);
|
||||
/* start transaction */
|
||||
spin_lock_irqsave(&ec->curr_lock, tmp);
|
||||
/* following two actions should be kept atomic */
|
||||
|
|
@ -967,6 +971,11 @@ int __init acpi_ec_ecdt_probe(void)
|
|||
/*
|
||||
* Generate a boot ec context
|
||||
*/
|
||||
if (dmi_name_in_vendors("Micro-Star") ||
|
||||
dmi_name_in_vendors("Notebook")) {
|
||||
pr_info(PREFIX "Enabling special treatment for EC from MSI.\n");
|
||||
EC_FLAGS_MSI = 1;
|
||||
}
|
||||
status = acpi_get_table(ACPI_SIG_ECDT, 1,
|
||||
(struct acpi_table_header **)&ecdt_ptr);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
|
|
|||
|
|
@ -277,7 +277,7 @@ int acpi_get_node(acpi_handle *handle)
|
|||
int pxm, node = -1;
|
||||
|
||||
pxm = acpi_get_pxm(handle);
|
||||
if (pxm >= 0)
|
||||
if (pxm >= 0 && pxm < MAX_PXM_DOMAINS)
|
||||
node = acpi_map_pxm_to_node(pxm);
|
||||
|
||||
return node;
|
||||
|
|
|
|||
|
|
@ -1317,54 +1317,6 @@ acpi_os_validate_interface (char *interface)
|
|||
return AE_SUPPORT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
|
||||
struct aml_port_desc {
|
||||
uint start;
|
||||
uint end;
|
||||
char* name;
|
||||
char warned;
|
||||
};
|
||||
|
||||
static struct aml_port_desc aml_invalid_port_list[] = {
|
||||
{0x20, 0x21, "PIC0", 0},
|
||||
{0xA0, 0xA1, "PIC1", 0},
|
||||
{0x4D0, 0x4D1, "ELCR", 0}
|
||||
};
|
||||
|
||||
/*
|
||||
* valid_aml_io_address()
|
||||
*
|
||||
* if valid, return true
|
||||
* else invalid, warn once, return false
|
||||
*/
|
||||
static bool valid_aml_io_address(uint address, uint length)
|
||||
{
|
||||
int i;
|
||||
int entries = sizeof(aml_invalid_port_list) / sizeof(struct aml_port_desc);
|
||||
|
||||
for (i = 0; i < entries; ++i) {
|
||||
if ((address >= aml_invalid_port_list[i].start &&
|
||||
address <= aml_invalid_port_list[i].end) ||
|
||||
(address + length >= aml_invalid_port_list[i].start &&
|
||||
address + length <= aml_invalid_port_list[i].end))
|
||||
{
|
||||
if (!aml_invalid_port_list[i].warned)
|
||||
{
|
||||
printk(KERN_ERR "ACPI: Denied BIOS AML access"
|
||||
" to invalid port 0x%x+0x%x (%s)\n",
|
||||
address, length,
|
||||
aml_invalid_port_list[i].name);
|
||||
aml_invalid_port_list[i].warned = 1;
|
||||
}
|
||||
return false; /* invalid */
|
||||
}
|
||||
}
|
||||
return true; /* valid */
|
||||
}
|
||||
#else
|
||||
static inline bool valid_aml_io_address(uint address, uint length) { return true; }
|
||||
#endif
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_os_validate_address
|
||||
|
|
@ -1394,8 +1346,6 @@ acpi_os_validate_address (
|
|||
|
||||
switch (space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
if (!valid_aml_io_address(address, length))
|
||||
return AE_AML_ILLEGAL_ADDRESS;
|
||||
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
|
||||
/* Only interference checks against SystemIO and SytemMemory
|
||||
are needed */
|
||||
|
|
|
|||
|
|
@ -378,6 +378,22 @@ static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
|
|||
DMI_MATCH(DMI_PRODUCT_NAME, "Macmini1,1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = init_old_suspend_ordering,
|
||||
.ident = "Asus Pundit P1-AH2 (M2N8L motherboard)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTek Computer INC."),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "M2N8L"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = init_set_sci_en_on_resume,
|
||||
.ident = "Toshiba Satellite L300",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"),
|
||||
},
|
||||
},
|
||||
{},
|
||||
};
|
||||
#endif /* CONFIG_SUSPEND */
|
||||
|
|
|
|||
|
|
@ -582,18 +582,18 @@ static const struct pci_device_id ahci_pci_tbl[] = {
|
|||
{ PCI_VDEVICE(NVIDIA, 0x0abd), board_ahci }, /* MCP79 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0abe), board_ahci }, /* MCP79 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0abf), board_ahci }, /* MCP79 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bc8), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bc9), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bca), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bcb), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bcc), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bcd), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bce), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bcf), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bc4), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bc5), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bc6), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0bc7), board_ahci }, /* MCP7B */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d84), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d85), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d86), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d87), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d88), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d89), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d8a), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d8b), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d8c), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d8d), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d8e), board_ahci }, /* MCP89 */
|
||||
{ PCI_VDEVICE(NVIDIA, 0x0d8f), board_ahci }, /* MCP89 */
|
||||
|
||||
/* SiS */
|
||||
{ PCI_VDEVICE(SI, 0x1184), board_ahci }, /* SiS 966 */
|
||||
|
|
|
|||
|
|
@ -1289,6 +1289,39 @@ static const int *__devinit piix_init_sata_map(struct pci_dev *pdev,
|
|||
return map;
|
||||
}
|
||||
|
||||
static bool piix_no_sidpr(struct ata_host *host)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(host->dev);
|
||||
|
||||
/*
|
||||
* Samsung DB-P70 only has three ATA ports exposed and
|
||||
* curiously the unconnected first port reports link online
|
||||
* while not responding to SRST protocol causing excessive
|
||||
* detection delay.
|
||||
*
|
||||
* Unfortunately, the system doesn't carry enough DMI
|
||||
* information to identify the machine but does have subsystem
|
||||
* vendor and device set. As it's unclear whether the
|
||||
* subsystem vendor/device is used only for this specific
|
||||
* board, the port can't be disabled solely with the
|
||||
* information; however, turning off SIDPR access works around
|
||||
* the problem. Turn it off.
|
||||
*
|
||||
* This problem is reported in bnc#441240.
|
||||
*
|
||||
* https://bugzilla.novell.com/show_bug.cgi?id=441420
|
||||
*/
|
||||
if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == 0x2920 &&
|
||||
pdev->subsystem_vendor == PCI_VENDOR_ID_SAMSUNG &&
|
||||
pdev->subsystem_device == 0xb049) {
|
||||
dev_printk(KERN_WARNING, host->dev,
|
||||
"Samsung DB-P70 detected, disabling SIDPR\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __devinit piix_init_sidpr(struct ata_host *host)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(host->dev);
|
||||
|
|
@ -1302,6 +1335,10 @@ static int __devinit piix_init_sidpr(struct ata_host *host)
|
|||
if (hpriv->map[i] == IDE)
|
||||
return 0;
|
||||
|
||||
/* is it blacklisted? */
|
||||
if (piix_no_sidpr(host))
|
||||
return 0;
|
||||
|
||||
if (!(host->ports[0]->flags & PIIX_FLAG_SIDPR))
|
||||
return 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -1322,14 +1322,16 @@ static u64 ata_id_n_sectors(const u16 *id)
|
|||
{
|
||||
if (ata_id_has_lba(id)) {
|
||||
if (ata_id_has_lba48(id))
|
||||
return ata_id_u64(id, 100);
|
||||
return ata_id_u64(id, ATA_ID_LBA_CAPACITY_2);
|
||||
else
|
||||
return ata_id_u32(id, 60);
|
||||
return ata_id_u32(id, ATA_ID_LBA_CAPACITY);
|
||||
} else {
|
||||
if (ata_id_current_chs_valid(id))
|
||||
return ata_id_u32(id, 57);
|
||||
return id[ATA_ID_CUR_CYLS] * id[ATA_ID_CUR_HEADS] *
|
||||
id[ATA_ID_CUR_SECTORS];
|
||||
else
|
||||
return id[1] * id[3] * id[6];
|
||||
return id[ATA_ID_CYLS] * id[ATA_ID_HEADS] *
|
||||
id[ATA_ID_SECTORS];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4612,7 +4614,7 @@ void ata_sg_clean(struct ata_queued_cmd *qc)
|
|||
VPRINTK("unmapping %u sg elements\n", qc->n_elem);
|
||||
|
||||
if (qc->n_elem)
|
||||
dma_unmap_sg(ap->dev, sg, qc->n_elem, dir);
|
||||
dma_unmap_sg(ap->dev, sg, qc->orig_n_elem, dir);
|
||||
|
||||
qc->flags &= ~ATA_QCFLAG_DMAMAP;
|
||||
qc->sg = NULL;
|
||||
|
|
@ -4727,7 +4729,7 @@ static int ata_sg_setup(struct ata_queued_cmd *qc)
|
|||
return -1;
|
||||
|
||||
DPRINTK("%d sg elements mapped\n", n_elem);
|
||||
|
||||
qc->orig_n_elem = qc->n_elem;
|
||||
qc->n_elem = n_elem;
|
||||
qc->flags |= ATA_QCFLAG_DMAMAP;
|
||||
|
||||
|
|
|
|||
|
|
@ -2423,11 +2423,14 @@ int ata_eh_reset(struct ata_link *link, int classify,
|
|||
}
|
||||
|
||||
/* prereset() might have cleared ATA_EH_RESET. If so,
|
||||
* bang classes and return.
|
||||
* bang classes, thaw and return.
|
||||
*/
|
||||
if (reset && !(ehc->i.action & ATA_EH_RESET)) {
|
||||
ata_for_each_dev(dev, link, ALL)
|
||||
classes[dev->devno] = ATA_DEV_NONE;
|
||||
if ((ap->pflags & ATA_PFLAG_FROZEN) &&
|
||||
ata_is_host_link(link))
|
||||
ata_eh_thaw_port(ap);
|
||||
rc = 0;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -2901,7 +2904,7 @@ static int atapi_eh_clear_ua(struct ata_device *dev)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < ATA_EH_UA_TRIES; i++) {
|
||||
u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
|
||||
u8 *sense_buffer = dev->link->ap->sector_buf;
|
||||
u8 sense_key = 0;
|
||||
unsigned int err_mask;
|
||||
|
||||
|
|
|
|||
|
|
@ -773,18 +773,32 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
|
|||
else
|
||||
iowrite32_rep(data_addr, buf, words);
|
||||
|
||||
/* Transfer trailing bytes, if any */
|
||||
if (unlikely(slop)) {
|
||||
__le32 pad;
|
||||
unsigned char pad[4];
|
||||
|
||||
/* Point buf to the tail of buffer */
|
||||
buf += buflen - slop;
|
||||
|
||||
/*
|
||||
* Use io*_rep() accessors here as well to avoid pointlessly
|
||||
* swapping bytes to and fro on the big endian machines...
|
||||
*/
|
||||
if (rw == READ) {
|
||||
pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
|
||||
memcpy(buf + buflen - slop, &pad, slop);
|
||||
if (slop < 3)
|
||||
ioread16_rep(data_addr, pad, 1);
|
||||
else
|
||||
ioread32_rep(data_addr, pad, 1);
|
||||
memcpy(buf, pad, slop);
|
||||
} else {
|
||||
memcpy(&pad, buf + buflen - slop, slop);
|
||||
iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
|
||||
memcpy(pad, buf, slop);
|
||||
if (slop < 3)
|
||||
iowrite16_rep(data_addr, pad, 1);
|
||||
else
|
||||
iowrite32_rep(data_addr, pad, 1);
|
||||
}
|
||||
words++;
|
||||
}
|
||||
return words << 2;
|
||||
return (buflen + 1) & ~1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
|
||||
|
||||
|
|
@ -2052,6 +2066,7 @@ static int ata_bus_softreset(struct ata_port *ap, unsigned int devmask,
|
|||
iowrite8(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
|
||||
udelay(20); /* FIXME: flush */
|
||||
iowrite8(ap->ctl, ioaddr->ctl_addr);
|
||||
ap->last_ctl = ap->ctl;
|
||||
|
||||
/* wait the port to become ready */
|
||||
return ata_sff_wait_after_reset(&ap->link, devmask, deadline);
|
||||
|
|
@ -2176,8 +2191,10 @@ void ata_sff_postreset(struct ata_link *link, unsigned int *classes)
|
|||
}
|
||||
|
||||
/* set up device control */
|
||||
if (ap->ioaddr.ctl_addr)
|
||||
if (ap->ioaddr.ctl_addr) {
|
||||
iowrite8(ap->ctl, ap->ioaddr.ctl_addr);
|
||||
ap->last_ctl = ap->ctl;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ata_sff_postreset);
|
||||
|
||||
|
|
@ -2520,6 +2537,7 @@ void ata_bus_reset(struct ata_port *ap)
|
|||
if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
|
||||
/* set up device control for ATA_FLAG_SATA_RESET */
|
||||
iowrite8(ap->ctl, ioaddr->ctl_addr);
|
||||
ap->last_ctl = ap->ctl;
|
||||
}
|
||||
|
||||
DPRINTK("EXIT\n");
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include <linux/libata.h>
|
||||
|
||||
#define DRV_NAME "pata_amd"
|
||||
#define DRV_VERSION "0.3.11"
|
||||
#define DRV_VERSION "0.4.1"
|
||||
|
||||
/**
|
||||
* timing_setup - shared timing computation and load
|
||||
|
|
@ -145,6 +145,13 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
|
|||
return ata_sff_prereset(link, deadline);
|
||||
}
|
||||
|
||||
/**
|
||||
* amd_cable_detect - report cable type
|
||||
* @ap: port
|
||||
*
|
||||
* AMD controller/BIOS setups record the cable type in word 0x42
|
||||
*/
|
||||
|
||||
static int amd_cable_detect(struct ata_port *ap)
|
||||
{
|
||||
static const u32 bitmask[2] = {0x03, 0x0C};
|
||||
|
|
@ -157,6 +164,40 @@ static int amd_cable_detect(struct ata_port *ap)
|
|||
return ATA_CBL_PATA40;
|
||||
}
|
||||
|
||||
/**
|
||||
* amd_fifo_setup - set the PIO FIFO for ATA/ATAPI
|
||||
* @ap: ATA interface
|
||||
* @adev: ATA device
|
||||
*
|
||||
* Set the PCI fifo for this device according to the devices present
|
||||
* on the bus at this point in time. We need to turn the post write buffer
|
||||
* off for ATAPI devices as we may need to issue a word sized write to the
|
||||
* device as the final I/O
|
||||
*/
|
||||
|
||||
static void amd_fifo_setup(struct ata_port *ap)
|
||||
{
|
||||
struct ata_device *adev;
|
||||
struct pci_dev *pdev = to_pci_dev(ap->host->dev);
|
||||
static const u8 fifobit[2] = { 0xC0, 0x30};
|
||||
u8 fifo = fifobit[ap->port_no];
|
||||
u8 r;
|
||||
|
||||
|
||||
ata_for_each_dev(adev, &ap->link, ENABLED) {
|
||||
if (adev->class == ATA_DEV_ATAPI)
|
||||
fifo = 0;
|
||||
}
|
||||
if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) /* FIFO is broken */
|
||||
fifo = 0;
|
||||
|
||||
/* On the later chips the read prefetch bits become no-op bits */
|
||||
pci_read_config_byte(pdev, 0x41, &r);
|
||||
r &= ~fifobit[ap->port_no];
|
||||
r |= fifo;
|
||||
pci_write_config_byte(pdev, 0x41, r);
|
||||
}
|
||||
|
||||
/**
|
||||
* amd33_set_piomode - set initial PIO mode data
|
||||
* @ap: ATA interface
|
||||
|
|
@ -167,21 +208,25 @@ static int amd_cable_detect(struct ata_port *ap)
|
|||
|
||||
static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
amd_fifo_setup(ap);
|
||||
timing_setup(ap, adev, 0x40, adev->pio_mode, 1);
|
||||
}
|
||||
|
||||
static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
amd_fifo_setup(ap);
|
||||
timing_setup(ap, adev, 0x40, adev->pio_mode, 2);
|
||||
}
|
||||
|
||||
static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
amd_fifo_setup(ap);
|
||||
timing_setup(ap, adev, 0x40, adev->pio_mode, 3);
|
||||
}
|
||||
|
||||
static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
||||
{
|
||||
amd_fifo_setup(ap);
|
||||
timing_setup(ap, adev, 0x40, adev->pio_mode, 4);
|
||||
}
|
||||
|
||||
|
|
@ -397,6 +442,16 @@ static struct ata_port_operations nv133_port_ops = {
|
|||
.set_dmamode = nv133_set_dmamode,
|
||||
};
|
||||
|
||||
static void amd_clear_fifo(struct pci_dev *pdev)
|
||||
{
|
||||
u8 fifo;
|
||||
/* Disable the FIFO, the FIFO logic will re-enable it as
|
||||
appropriate */
|
||||
pci_read_config_byte(pdev, 0x41, &fifo);
|
||||
fifo &= 0x0F;
|
||||
pci_write_config_byte(pdev, 0x41, fifo);
|
||||
}
|
||||
|
||||
static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
||||
{
|
||||
static const struct ata_port_info info[10] = {
|
||||
|
|
@ -503,14 +558,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
|
|||
|
||||
if (type < 3)
|
||||
ata_pci_bmdma_clear_simplex(pdev);
|
||||
|
||||
/* Check for AMD7411 */
|
||||
if (type == 3)
|
||||
/* FIFO is broken */
|
||||
pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
|
||||
else
|
||||
pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD)
|
||||
amd_clear_fifo(pdev);
|
||||
/* Cable detection on Nvidia chips doesn't work too well,
|
||||
* cache BIOS programmed UDMA mode.
|
||||
*/
|
||||
|
|
@ -536,18 +585,11 @@ static int amd_reinit_one(struct pci_dev *pdev)
|
|||
return rc;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_AMD) {
|
||||
u8 fifo;
|
||||
pci_read_config_byte(pdev, 0x41, &fifo);
|
||||
if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
|
||||
/* FIFO is broken */
|
||||
pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
|
||||
else
|
||||
pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
|
||||
amd_clear_fifo(pdev);
|
||||
if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 ||
|
||||
pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
|
||||
ata_pci_bmdma_clear_simplex(pdev);
|
||||
}
|
||||
|
||||
ata_host_resume(host);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -557,6 +557,9 @@ static unsigned int it821x_read_id(struct ata_device *adev,
|
|||
id[83] |= 0x4400; /* Word 83 is valid and LBA48 */
|
||||
id[86] |= 0x0400; /* LBA48 on */
|
||||
id[ATA_ID_MAJOR_VER] |= 0x1F;
|
||||
/* Clear the serial number because it's different each boot
|
||||
which breaks validation on resume */
|
||||
memset(&id[ATA_ID_SERNO], 0x20, ATA_ID_SERNO_LEN);
|
||||
}
|
||||
return err_mask;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -283,9 +283,10 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
|
|||
static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
|
||||
unsigned char *buf, unsigned int buflen, int rw)
|
||||
{
|
||||
if (ata_id_has_dword_io(dev->id)) {
|
||||
int slop = buflen & 3;
|
||||
/* 32bit I/O capable *and* we need to write a whole number of dwords */
|
||||
if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)) {
|
||||
struct ata_port *ap = dev->link->ap;
|
||||
int slop = buflen & 3;
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
|
@ -735,7 +736,7 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
|
|||
struct ata_port *ap = adev->link->ap;
|
||||
int slop = buflen & 3;
|
||||
|
||||
if (ata_id_has_dword_io(adev->id)) {
|
||||
if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)) {
|
||||
if (rw == WRITE)
|
||||
iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -110,7 +110,8 @@ static const struct via_isa_bridge {
|
|||
{ "vt8237s", PCI_DEVICE_ID_VIA_8237S, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "vt8251", PCI_DEVICE_ID_VIA_8251, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "cx700", PCI_DEVICE_ID_VIA_CX700, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
|
||||
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
|
||||
{ "vt6410", PCI_DEVICE_ID_VIA_6410, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
|
||||
{ "vt6415", PCI_DEVICE_ID_VIA_6415, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
|
||||
{ "vt8237a", PCI_DEVICE_ID_VIA_8237A, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "vt8237", PCI_DEVICE_ID_VIA_8237, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
{ "vt8235", PCI_DEVICE_ID_VIA_8235, 0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
|
||||
|
|
@ -593,6 +594,7 @@ static int via_reinit_one(struct pci_dev *pdev)
|
|||
#endif
|
||||
|
||||
static const struct pci_device_id via[] = {
|
||||
{ PCI_VDEVICE(VIA, 0x0415), },
|
||||
{ PCI_VDEVICE(VIA, 0x0571), },
|
||||
{ PCI_VDEVICE(VIA, 0x0581), },
|
||||
{ PCI_VDEVICE(VIA, 0x1571), },
|
||||
|
|
|
|||
|
|
@ -2218,12 +2218,13 @@ static irqreturn_t mv_interrupt(int irq, void *dev_instance)
|
|||
else
|
||||
handled = mv_host_intr(host, pending_irqs);
|
||||
}
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
/* for MSI: unmask; interrupt cause bits will retrigger now */
|
||||
if (using_msi)
|
||||
writel(hpriv->main_irq_mask, hpriv->main_irq_mask_addr);
|
||||
|
||||
spin_unlock(&host->lock);
|
||||
|
||||
return IRQ_RETVAL(handled);
|
||||
}
|
||||
|
||||
|
|
@ -3114,19 +3115,17 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
|
|||
writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
|
||||
}
|
||||
|
||||
if (!IS_SOC(hpriv)) {
|
||||
/* Clear any currently outstanding host interrupt conditions */
|
||||
writelfl(0, mmio + hpriv->irq_cause_ofs);
|
||||
/* Clear any currently outstanding host interrupt conditions */
|
||||
writelfl(0, mmio + hpriv->irq_cause_ofs);
|
||||
|
||||
/* and unmask interrupt generation for host regs */
|
||||
writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
|
||||
/* and unmask interrupt generation for host regs */
|
||||
writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
|
||||
|
||||
/*
|
||||
* enable only global host interrupts for now.
|
||||
* The per-port interrupts get done later as ports are set up.
|
||||
*/
|
||||
mv_set_main_irq_mask(host, 0, PCI_ERR);
|
||||
}
|
||||
/*
|
||||
* enable only global host interrupts for now.
|
||||
* The per-port interrupts get done later as ports are set up.
|
||||
*/
|
||||
mv_set_main_irq_mask(host, 0, PCI_ERR);
|
||||
done:
|
||||
return rc;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -421,19 +421,21 @@ static struct ata_port_operations nv_generic_ops = {
|
|||
.hardreset = ATA_OP_NULL,
|
||||
};
|
||||
|
||||
/* OSDL bz3352 reports that nf2/3 controllers can't determine device
|
||||
* signature reliably. Also, the following thread reports detection
|
||||
* failure on cold boot with the standard debouncing timing.
|
||||
/* 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
|
||||
*
|
||||
* Debounce with hotplug timing and request follow-up SRST.
|
||||
* 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_common_ops,
|
||||
.inherits = &nv_generic_ops,
|
||||
.freeze = nv_nf2_freeze,
|
||||
.thaw = nv_nf2_thaw,
|
||||
.hardreset = nv_noclassify_hardreset,
|
||||
};
|
||||
|
||||
/* For initial probing after boot and hot plugging, hardreset mostly
|
||||
|
|
@ -2521,7 +2523,7 @@ static void __exit nv_exit(void)
|
|||
module_init(nv_init);
|
||||
module_exit(nv_exit);
|
||||
module_param_named(adma, adma_enabled, bool, 0444);
|
||||
MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: true)");
|
||||
MODULE_PARM_DESC(adma, "Enable use of ADMA (Default: false)");
|
||||
module_param_named(swncq, swncq_enabled, bool, 0444);
|
||||
MODULE_PARM_DESC(swncq, "Enable use of SWNCQ (Default: true)");
|
||||
|
||||
|
|
|
|||
|
|
@ -2519,8 +2519,8 @@ fore200e_load_and_start_fw(struct fore200e* fore200e)
|
|||
return err;
|
||||
|
||||
sprintf(buf, "%s%s", fore200e->bus->proc_name, FW_EXT);
|
||||
if (request_firmware(&firmware, buf, device) == 1) {
|
||||
printk(FORE200E "missing %s firmware image\n", fore200e->bus->model_name);
|
||||
if ((err = request_firmware(&firmware, buf, device)) < 0) {
|
||||
printk(FORE200E "problem loading firmware image %s\n", fore200e->bus->model_name);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -901,7 +901,7 @@ static int __devinit eeprom_read(struct lanai_dev *lanai)
|
|||
clock_l(); udelay(5);
|
||||
for (i = 128; i != 0; i >>= 1) { /* write command out */
|
||||
tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) |
|
||||
(data & i) ? CONFIG1_PROMDATA : 0;
|
||||
((data & i) ? CONFIG1_PROMDATA : 0);
|
||||
if (lanai->conf1 != tmp) {
|
||||
set_config1(tmp);
|
||||
udelay(5); /* Let new data settle */
|
||||
|
|
|
|||
|
|
@ -88,8 +88,6 @@ extern void driver_detach(struct device_driver *drv);
|
|||
extern int driver_probe_device(struct device_driver *drv, struct device *dev);
|
||||
|
||||
extern void sysdev_shutdown(void);
|
||||
extern int sysdev_suspend(pm_message_t state);
|
||||
extern int sysdev_resume(void);
|
||||
|
||||
extern char *make_class_name(const char *name, struct kobject *kobj);
|
||||
|
||||
|
|
|
|||
|
|
@ -18,9 +18,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/async.h>
|
||||
|
||||
#include "base.h"
|
||||
#include "power/power.h"
|
||||
|
|
@ -167,6 +169,21 @@ int driver_probe_done(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* wait_for_device_probe
|
||||
* Wait for device probing to be completed.
|
||||
*
|
||||
* Note: this function polls at 100 msec intervals.
|
||||
*/
|
||||
int wait_for_device_probe(void)
|
||||
{
|
||||
/* wait for the known devices to complete their probing */
|
||||
while (driver_probe_done() != 0)
|
||||
msleep(100);
|
||||
async_synchronize_full();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* driver_probe_device - attempt to bind device & driver together
|
||||
* @drv: driver to bind a device to
|
||||
|
|
|
|||
|
|
@ -303,7 +303,7 @@ int unregister_mem_sect_under_nodes(struct memory_block *mem_blk)
|
|||
sect_start_pfn = section_nr_to_pfn(mem_blk->phys_index);
|
||||
sect_end_pfn = sect_start_pfn + PAGES_PER_SECTION - 1;
|
||||
for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) {
|
||||
unsigned int nid;
|
||||
int nid;
|
||||
|
||||
nid = get_nid_for_pfn(pfn);
|
||||
if (nid < 0)
|
||||
|
|
|
|||
|
|
@ -333,7 +333,6 @@ static void dpm_power_up(pm_message_t state)
|
|||
*/
|
||||
void device_power_up(pm_message_t state)
|
||||
{
|
||||
sysdev_resume();
|
||||
dpm_power_up(state);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(device_power_up);
|
||||
|
|
@ -577,8 +576,6 @@ int device_power_down(pm_message_t state)
|
|||
}
|
||||
dev->power.status = DPM_OFF_IRQ;
|
||||
}
|
||||
if (!error)
|
||||
error = sysdev_suspend(state);
|
||||
if (error)
|
||||
dpm_power_up(resume_event(state));
|
||||
return error;
|
||||
|
|
|
|||
|
|
@ -303,7 +303,6 @@ void sysdev_unregister(struct sys_device * sysdev)
|
|||
* is guaranteed by virtue of the fact that child devices are registered
|
||||
* after their parents.
|
||||
*/
|
||||
|
||||
void sysdev_shutdown(void)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
|
|
@ -363,7 +362,6 @@ static void __sysdev_resume(struct sys_device *dev)
|
|||
* This is only called by the device PM core, so we let them handle
|
||||
* all synchronization.
|
||||
*/
|
||||
|
||||
int sysdev_suspend(pm_message_t state)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
|
|
@ -432,7 +430,7 @@ aux_driver:
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysdev_suspend);
|
||||
|
||||
/**
|
||||
* sysdev_resume - Bring system devices back to life.
|
||||
|
|
@ -442,7 +440,6 @@ aux_driver:
|
|||
*
|
||||
* Note: Interrupts are disabled when called.
|
||||
*/
|
||||
|
||||
int sysdev_resume(void)
|
||||
{
|
||||
struct sysdev_class * cls;
|
||||
|
|
@ -463,7 +460,7 @@ int sysdev_resume(void)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(sysdev_resume);
|
||||
|
||||
int __init system_bus_init(void)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o
|
|||
obj-$(CONFIG_BLK_DEV_FD) += floppy.o
|
||||
obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o
|
||||
obj-$(CONFIG_PS3_DISK) += ps3disk.o
|
||||
obj-$(CONFIG_PS3_VRAM) += ps3vram.o
|
||||
obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o
|
||||
obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o
|
||||
obj-$(CONFIG_BLK_DEV_RAM) += brd.o
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
enum {
|
||||
AOECMD_ATA,
|
||||
AOECMD_CFG,
|
||||
AOECMD_VEND_MIN = 0xf0,
|
||||
|
||||
AOEFL_RSP = (1<<3),
|
||||
AOEFL_ERR = (1<<2),
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ skbfree(struct sk_buff *skb)
|
|||
return;
|
||||
while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0)
|
||||
msleep(Sms);
|
||||
if (i <= 0) {
|
||||
if (i < 0) {
|
||||
printk(KERN_ERR
|
||||
"aoe: %s holds ref: %s\n",
|
||||
skb->dev ? skb->dev->name : "netif",
|
||||
|
|
|
|||
|
|
@ -142,6 +142,8 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
|
|||
aoecmd_cfg_rsp(skb);
|
||||
break;
|
||||
default:
|
||||
if (h->cmd >= AOECMD_VEND_MIN)
|
||||
break; /* don't complain about vendor commands */
|
||||
printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
|
||||
}
|
||||
exit:
|
||||
|
|
|
|||
|
|
@ -1730,7 +1730,7 @@ static int __init fd_test_drive_present( int drive )
|
|||
|
||||
timeout = jiffies + 2*HZ+HZ/2;
|
||||
while (time_before(jiffies, timeout))
|
||||
if (!(mfp.par_dt_reg & 0x20))
|
||||
if (!(st_mfp.par_dt_reg & 0x20))
|
||||
break;
|
||||
|
||||
status = FDC_READ( FDCREG_STATUS );
|
||||
|
|
@ -1747,7 +1747,7 @@ static int __init fd_test_drive_present( int drive )
|
|||
/* dummy seek command to make WP bit accessible */
|
||||
FDC_WRITE( FDCREG_DATA, 0 );
|
||||
FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );
|
||||
while( mfp.par_dt_reg & 0x20 )
|
||||
while( st_mfp.par_dt_reg & 0x20 )
|
||||
;
|
||||
status = FDC_READ( FDCREG_STATUS );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3390,6 +3390,203 @@ static void free_hba(int i)
|
|||
kfree(p);
|
||||
}
|
||||
|
||||
/* Send a message CDB to the firmware. */
|
||||
static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, unsigned char type)
|
||||
{
|
||||
typedef struct {
|
||||
CommandListHeader_struct CommandHeader;
|
||||
RequestBlock_struct Request;
|
||||
ErrDescriptor_struct ErrorDescriptor;
|
||||
} Command;
|
||||
static const size_t cmd_sz = sizeof(Command) + sizeof(ErrorInfo_struct);
|
||||
Command *cmd;
|
||||
dma_addr_t paddr64;
|
||||
uint32_t paddr32, tag;
|
||||
void __iomem *vaddr;
|
||||
int i, err;
|
||||
|
||||
vaddr = ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
|
||||
if (vaddr == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* The Inbound Post Queue only accepts 32-bit physical addresses for the
|
||||
CCISS commands, so they must be allocated from the lower 4GiB of
|
||||
memory. */
|
||||
err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
|
||||
if (err) {
|
||||
iounmap(vaddr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
|
||||
if (cmd == NULL) {
|
||||
iounmap(vaddr);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* This must fit, because of the 32-bit consistent DMA mask. Also,
|
||||
although there's no guarantee, we assume that the address is at
|
||||
least 4-byte aligned (most likely, it's page-aligned). */
|
||||
paddr32 = paddr64;
|
||||
|
||||
cmd->CommandHeader.ReplyQueue = 0;
|
||||
cmd->CommandHeader.SGList = 0;
|
||||
cmd->CommandHeader.SGTotal = 0;
|
||||
cmd->CommandHeader.Tag.lower = paddr32;
|
||||
cmd->CommandHeader.Tag.upper = 0;
|
||||
memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
|
||||
|
||||
cmd->Request.CDBLen = 16;
|
||||
cmd->Request.Type.Type = TYPE_MSG;
|
||||
cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE;
|
||||
cmd->Request.Type.Direction = XFER_NONE;
|
||||
cmd->Request.Timeout = 0; /* Don't time out */
|
||||
cmd->Request.CDB[0] = opcode;
|
||||
cmd->Request.CDB[1] = type;
|
||||
memset(&cmd->Request.CDB[2], 0, 14); /* the rest of the CDB is reserved */
|
||||
|
||||
cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(Command);
|
||||
cmd->ErrorDescriptor.Addr.upper = 0;
|
||||
cmd->ErrorDescriptor.Len = sizeof(ErrorInfo_struct);
|
||||
|
||||
writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
|
||||
if ((tag & ~3) == paddr32)
|
||||
break;
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
}
|
||||
|
||||
iounmap(vaddr);
|
||||
|
||||
/* we leak the DMA buffer here ... no choice since the controller could
|
||||
still complete the command. */
|
||||
if (i == 10) {
|
||||
printk(KERN_ERR "cciss: controller message %02x:%02x timed out\n",
|
||||
opcode, type);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
|
||||
|
||||
if (tag & 2) {
|
||||
printk(KERN_ERR "cciss: controller message %02x:%02x failed\n",
|
||||
opcode, type);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "cciss: controller message %02x:%02x succeeded\n",
|
||||
opcode, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
|
||||
#define cciss_noop(p) cciss_message(p, 3, 0)
|
||||
|
||||
static __devinit int cciss_reset_msi(struct pci_dev *pdev)
|
||||
{
|
||||
/* the #defines are stolen from drivers/pci/msi.h. */
|
||||
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
|
||||
#define PCI_MSIX_FLAGS_ENABLE (1 << 15)
|
||||
|
||||
int pos;
|
||||
u16 control = 0;
|
||||
|
||||
pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
|
||||
if (pos) {
|
||||
pci_read_config_word(pdev, msi_control_reg(pos), &control);
|
||||
if (control & PCI_MSI_FLAGS_ENABLE) {
|
||||
printk(KERN_INFO "cciss: resetting MSI\n");
|
||||
pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
|
||||
if (pos) {
|
||||
pci_read_config_word(pdev, msi_control_reg(pos), &control);
|
||||
if (control & PCI_MSIX_FLAGS_ENABLE) {
|
||||
printk(KERN_INFO "cciss: resetting MSI-X\n");
|
||||
pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This does a hard reset of the controller using PCI power management
|
||||
* states. */
|
||||
static __devinit int cciss_hard_reset_controller(struct pci_dev *pdev)
|
||||
{
|
||||
u16 pmcsr, saved_config_space[32];
|
||||
int i, pos;
|
||||
|
||||
printk(KERN_INFO "cciss: using PCI PM to reset controller\n");
|
||||
|
||||
/* This is very nearly the same thing as
|
||||
|
||||
pci_save_state(pci_dev);
|
||||
pci_set_power_state(pci_dev, PCI_D3hot);
|
||||
pci_set_power_state(pci_dev, PCI_D0);
|
||||
pci_restore_state(pci_dev);
|
||||
|
||||
but we can't use these nice canned kernel routines on
|
||||
kexec, because they also check the MSI/MSI-X state in PCI
|
||||
configuration space and do the wrong thing when it is
|
||||
set/cleared. Also, the pci_save/restore_state functions
|
||||
violate the ordering requirements for restoring the
|
||||
configuration space from the CCISS document (see the
|
||||
comment below). So we roll our own .... */
|
||||
|
||||
for (i = 0; i < 32; i++)
|
||||
pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
|
||||
|
||||
pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
|
||||
if (pos == 0) {
|
||||
printk(KERN_ERR "cciss_reset_controller: PCI PM not supported\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* Quoting from the Open CISS Specification: "The Power
|
||||
* Management Control/Status Register (CSR) controls the power
|
||||
* state of the device. The normal operating state is D0,
|
||||
* CSR=00h. The software off state is D3, CSR=03h. To reset
|
||||
* the controller, place the interface device in D3 then to
|
||||
* D0, this causes a secondary PCI reset which will reset the
|
||||
* controller." */
|
||||
|
||||
/* enter the D3hot power management state */
|
||||
pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
|
||||
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
|
||||
pmcsr |= PCI_D3hot;
|
||||
pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
|
||||
|
||||
schedule_timeout_uninterruptible(HZ >> 1);
|
||||
|
||||
/* enter the D0 power management state */
|
||||
pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
|
||||
pmcsr |= PCI_D0;
|
||||
pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
|
||||
|
||||
schedule_timeout_uninterruptible(HZ >> 1);
|
||||
|
||||
/* Restore the PCI configuration space. The Open CISS
|
||||
* Specification says, "Restore the PCI Configuration
|
||||
* Registers, offsets 00h through 60h. It is important to
|
||||
* restore the command register, 16-bits at offset 04h,
|
||||
* last. Do not restore the configuration status register,
|
||||
* 16-bits at offset 06h." Note that the offset is 2*i. */
|
||||
for (i = 0; i < 32; i++) {
|
||||
if (i == 2 || i == 3)
|
||||
continue;
|
||||
pci_write_config_word(pdev, 2*i, saved_config_space[i]);
|
||||
}
|
||||
wmb();
|
||||
pci_write_config_word(pdev, 4, saved_config_space[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is it. Find all the controllers and register them. I really hate
|
||||
* stealing all these major device numbers.
|
||||
|
|
@ -3404,6 +3601,26 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
|
|||
int dac, return_code;
|
||||
InquiryData_struct *inq_buff = NULL;
|
||||
|
||||
if (reset_devices) {
|
||||
/* Reset the controller with a PCI power-cycle */
|
||||
if (cciss_hard_reset_controller(pdev) || cciss_reset_msi(pdev))
|
||||
return -ENODEV;
|
||||
|
||||
/* Now try to get the controller to respond to a no-op. Some
|
||||
devices (notably the HP Smart Array 5i Controller) need
|
||||
up to 30 seconds to respond. */
|
||||
for (i=0; i<30; i++) {
|
||||
if (cciss_noop(pdev) == 0)
|
||||
break;
|
||||
|
||||
schedule_timeout_uninterruptible(HZ);
|
||||
}
|
||||
if (i == 30) {
|
||||
printk(KERN_ERR "cciss: controller seems dead\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
|
||||
i = alloc_cciss_hba();
|
||||
if (i < 0)
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -558,6 +558,8 @@ static void process_fd_request(void);
|
|||
static void recalibrate_floppy(void);
|
||||
static void floppy_shutdown(unsigned long);
|
||||
|
||||
static int floppy_request_regions(int);
|
||||
static void floppy_release_regions(int);
|
||||
static int floppy_grab_irq_and_dma(void);
|
||||
static void floppy_release_irq_and_dma(void);
|
||||
|
||||
|
|
@ -4274,8 +4276,7 @@ static int __init floppy_init(void)
|
|||
FDCS->rawcmd = 2;
|
||||
if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
|
||||
/* free ioports reserved by floppy_grab_irq_and_dma() */
|
||||
release_region(FDCS->address + 2, 4);
|
||||
release_region(FDCS->address + 7, 1);
|
||||
floppy_release_regions(fdc);
|
||||
FDCS->address = -1;
|
||||
FDCS->version = FDC_NONE;
|
||||
continue;
|
||||
|
|
@ -4284,8 +4285,7 @@ static int __init floppy_init(void)
|
|||
FDCS->version = get_fdc_version();
|
||||
if (FDCS->version == FDC_NONE) {
|
||||
/* free ioports reserved by floppy_grab_irq_and_dma() */
|
||||
release_region(FDCS->address + 2, 4);
|
||||
release_region(FDCS->address + 7, 1);
|
||||
floppy_release_regions(fdc);
|
||||
FDCS->address = -1;
|
||||
continue;
|
||||
}
|
||||
|
|
@ -4358,6 +4358,47 @@ out_put_disk:
|
|||
|
||||
static DEFINE_SPINLOCK(floppy_usage_lock);
|
||||
|
||||
static const struct io_region {
|
||||
int offset;
|
||||
int size;
|
||||
} io_regions[] = {
|
||||
{ 2, 1 },
|
||||
/* address + 3 is sometimes reserved by pnp bios for motherboard */
|
||||
{ 4, 2 },
|
||||
/* address + 6 is reserved, and may be taken by IDE.
|
||||
* Unfortunately, Adaptec doesn't know this :-(, */
|
||||
{ 7, 1 },
|
||||
};
|
||||
|
||||
static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
|
||||
{
|
||||
while (p != io_regions) {
|
||||
p--;
|
||||
release_region(FDCS->address + p->offset, p->size);
|
||||
}
|
||||
}
|
||||
|
||||
#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
|
||||
|
||||
static int floppy_request_regions(int fdc)
|
||||
{
|
||||
const struct io_region *p;
|
||||
|
||||
for (p = io_regions; p < ARRAY_END(io_regions); p++) {
|
||||
if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
|
||||
DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
|
||||
floppy_release_allocated_regions(fdc, p);
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void floppy_release_regions(int fdc)
|
||||
{
|
||||
floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
|
||||
}
|
||||
|
||||
static int floppy_grab_irq_and_dma(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
|
@ -4399,18 +4440,8 @@ static int floppy_grab_irq_and_dma(void)
|
|||
|
||||
for (fdc = 0; fdc < N_FDC; fdc++) {
|
||||
if (FDCS->address != -1) {
|
||||
if (!request_region(FDCS->address + 2, 4, "floppy")) {
|
||||
DPRINT("Floppy io-port 0x%04lx in use\n",
|
||||
FDCS->address + 2);
|
||||
goto cleanup1;
|
||||
}
|
||||
if (!request_region(FDCS->address + 7, 1, "floppy DIR")) {
|
||||
DPRINT("Floppy io-port 0x%04lx in use\n",
|
||||
FDCS->address + 7);
|
||||
goto cleanup2;
|
||||
}
|
||||
/* address + 6 is reserved, and may be taken by IDE.
|
||||
* Unfortunately, Adaptec doesn't know this :-(, */
|
||||
if (floppy_request_regions(fdc))
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
for (fdc = 0; fdc < N_FDC; fdc++) {
|
||||
|
|
@ -4432,15 +4463,11 @@ static int floppy_grab_irq_and_dma(void)
|
|||
fdc = 0;
|
||||
irqdma_allocated = 1;
|
||||
return 0;
|
||||
cleanup2:
|
||||
release_region(FDCS->address + 2, 4);
|
||||
cleanup1:
|
||||
cleanup:
|
||||
fd_free_irq();
|
||||
fd_free_dma();
|
||||
while (--fdc >= 0) {
|
||||
release_region(FDCS->address + 2, 4);
|
||||
release_region(FDCS->address + 7, 1);
|
||||
}
|
||||
while (--fdc >= 0)
|
||||
floppy_release_regions(fdc);
|
||||
spin_lock_irqsave(&floppy_usage_lock, flags);
|
||||
usage_count--;
|
||||
spin_unlock_irqrestore(&floppy_usage_lock, flags);
|
||||
|
|
@ -4501,10 +4528,8 @@ static void floppy_release_irq_and_dma(void)
|
|||
#endif
|
||||
old_fdc = fdc;
|
||||
for (fdc = 0; fdc < N_FDC; fdc++)
|
||||
if (FDCS->address != -1) {
|
||||
release_region(FDCS->address + 2, 4);
|
||||
release_region(FDCS->address + 7, 1);
|
||||
}
|
||||
if (FDCS->address != -1)
|
||||
floppy_release_regions(fdc);
|
||||
fdc = old_fdc;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -392,8 +392,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
|
|||
struct loop_device *lo = p->lo;
|
||||
struct page *page = buf->page;
|
||||
sector_t IV;
|
||||
size_t size;
|
||||
int ret;
|
||||
int size, ret;
|
||||
|
||||
ret = buf->ops->confirm(pipe, buf);
|
||||
if (unlikely(ret))
|
||||
|
|
|
|||
|
|
@ -549,6 +549,15 @@ static void do_nbd_request(struct request_queue * q)
|
|||
|
||||
BUG_ON(lo->magic != LO_MAGIC);
|
||||
|
||||
if (unlikely(!lo->sock)) {
|
||||
printk(KERN_ERR "%s: Attempted send on closed socket\n",
|
||||
lo->disk->disk_name);
|
||||
req->errors++;
|
||||
nbd_end_request(req);
|
||||
spin_lock_irq(q->queue_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
spin_lock_irq(&lo->queue_lock);
|
||||
list_add_tail(&req->queuelist, &lo->waiting_queue);
|
||||
spin_unlock_irq(&lo->queue_lock);
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ static void xs(char *buf, char *targ, int len)
|
|||
|
||||
for (k = 0; k < len; k++) {
|
||||
char c = *buf++;
|
||||
if (c != ' ' || c != l)
|
||||
if (c != ' ' && c != l)
|
||||
l = *targ++ = c;
|
||||
}
|
||||
if (l == ' ')
|
||||
|
|
|
|||
865
drivers/block/ps3vram.c
Normal file
865
drivers/block/ps3vram.c
Normal file
|
|
@ -0,0 +1,865 @@
|
|||
/*
|
||||
* ps3vram - Use extra PS3 video ram as MTD block device.
|
||||
*
|
||||
* Copyright 2009 Sony Corporation
|
||||
*
|
||||
* Based on the MTD ps3vram driver, which is
|
||||
* Copyright (c) 2007-2008 Jim Paris <jim@jtan.com>
|
||||
* Added support RSX DMA Vivien Chappelier <vivien.chappelier@free.fr>
|
||||
*/
|
||||
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <asm/firmware.h>
|
||||
#include <asm/lv1call.h>
|
||||
#include <asm/ps3.h>
|
||||
|
||||
|
||||
#define DEVICE_NAME "ps3vram"
|
||||
|
||||
|
||||
#define XDR_BUF_SIZE (2 * 1024 * 1024) /* XDR buffer (must be 1MiB aligned) */
|
||||
#define XDR_IOIF 0x0c000000
|
||||
|
||||
#define FIFO_BASE XDR_IOIF
|
||||
#define FIFO_SIZE (64 * 1024)
|
||||
|
||||
#define DMA_PAGE_SIZE (4 * 1024)
|
||||
|
||||
#define CACHE_PAGE_SIZE (256 * 1024)
|
||||
#define CACHE_PAGE_COUNT ((XDR_BUF_SIZE - FIFO_SIZE) / CACHE_PAGE_SIZE)
|
||||
|
||||
#define CACHE_OFFSET CACHE_PAGE_SIZE
|
||||
#define FIFO_OFFSET 0
|
||||
|
||||
#define CTRL_PUT 0x10
|
||||
#define CTRL_GET 0x11
|
||||
#define CTRL_TOP 0x15
|
||||
|
||||
#define UPLOAD_SUBCH 1
|
||||
#define DOWNLOAD_SUBCH 2
|
||||
|
||||
#define NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN 0x0000030c
|
||||
#define NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY 0x00000104
|
||||
|
||||
#define L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT 0x601
|
||||
|
||||
#define CACHE_PAGE_PRESENT 1
|
||||
#define CACHE_PAGE_DIRTY 2
|
||||
|
||||
struct ps3vram_tag {
|
||||
unsigned int address;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
struct ps3vram_cache {
|
||||
unsigned int page_count;
|
||||
unsigned int page_size;
|
||||
struct ps3vram_tag *tags;
|
||||
unsigned int hit;
|
||||
unsigned int miss;
|
||||
};
|
||||
|
||||
struct ps3vram_priv {
|
||||
struct request_queue *queue;
|
||||
struct gendisk *gendisk;
|
||||
|
||||
u64 size;
|
||||
|
||||
u64 memory_handle;
|
||||
u64 context_handle;
|
||||
u32 *ctrl;
|
||||
u32 *reports;
|
||||
u8 __iomem *ddr_base;
|
||||
u8 *xdr_buf;
|
||||
|
||||
u32 *fifo_base;
|
||||
u32 *fifo_ptr;
|
||||
|
||||
struct ps3vram_cache cache;
|
||||
|
||||
/* Used to serialize cache/DMA operations */
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
|
||||
static int ps3vram_major;
|
||||
|
||||
|
||||
static struct block_device_operations ps3vram_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
#define DMA_NOTIFIER_HANDLE_BASE 0x66604200 /* first DMA notifier handle */
|
||||
#define DMA_NOTIFIER_OFFSET_BASE 0x1000 /* first DMA notifier offset */
|
||||
#define DMA_NOTIFIER_SIZE 0x40
|
||||
#define NOTIFIER 7 /* notifier used for completion report */
|
||||
|
||||
static char *size = "256M";
|
||||
module_param(size, charp, 0);
|
||||
MODULE_PARM_DESC(size, "memory size");
|
||||
|
||||
static u32 *ps3vram_get_notifier(u32 *reports, int notifier)
|
||||
{
|
||||
return (void *)reports + DMA_NOTIFIER_OFFSET_BASE +
|
||||
DMA_NOTIFIER_SIZE * notifier;
|
||||
}
|
||||
|
||||
static void ps3vram_notifier_reset(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
notify[i] = 0xffffffff;
|
||||
}
|
||||
|
||||
static int ps3vram_notifier_wait(struct ps3_system_bus_device *dev,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
u32 *notify = ps3vram_get_notifier(priv->reports, NOTIFIER);
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
|
||||
do {
|
||||
if (!notify[3])
|
||||
return 0;
|
||||
msleep(1);
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void ps3vram_init_ring(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
|
||||
priv->ctrl[CTRL_GET] = FIFO_BASE + FIFO_OFFSET;
|
||||
}
|
||||
|
||||
static int ps3vram_wait_ring(struct ps3_system_bus_device *dev,
|
||||
unsigned int timeout_ms)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
|
||||
|
||||
do {
|
||||
if (priv->ctrl[CTRL_PUT] == priv->ctrl[CTRL_GET])
|
||||
return 0;
|
||||
msleep(1);
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
dev_warn(&dev->core, "FIFO timeout (%08x/%08x/%08x)\n",
|
||||
priv->ctrl[CTRL_PUT], priv->ctrl[CTRL_GET],
|
||||
priv->ctrl[CTRL_TOP]);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void ps3vram_out_ring(struct ps3vram_priv *priv, u32 data)
|
||||
{
|
||||
*(priv->fifo_ptr)++ = data;
|
||||
}
|
||||
|
||||
static void ps3vram_begin_ring(struct ps3vram_priv *priv, u32 chan, u32 tag,
|
||||
u32 size)
|
||||
{
|
||||
ps3vram_out_ring(priv, (size << 18) | (chan << 13) | tag);
|
||||
}
|
||||
|
||||
static void ps3vram_rewind_ring(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
int status;
|
||||
|
||||
ps3vram_out_ring(priv, 0x20000000 | (FIFO_BASE + FIFO_OFFSET));
|
||||
|
||||
priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET;
|
||||
|
||||
/* asking the HV for a blit will kick the FIFO */
|
||||
status = lv1_gpu_context_attribute(priv->context_handle,
|
||||
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
|
||||
0, 0, 0);
|
||||
if (status)
|
||||
dev_err(&dev->core,
|
||||
"%s: lv1_gpu_context_attribute failed %d\n", __func__,
|
||||
status);
|
||||
|
||||
priv->fifo_ptr = priv->fifo_base;
|
||||
}
|
||||
|
||||
static void ps3vram_fire_ring(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
int status;
|
||||
|
||||
mutex_lock(&ps3_gpu_mutex);
|
||||
|
||||
priv->ctrl[CTRL_PUT] = FIFO_BASE + FIFO_OFFSET +
|
||||
(priv->fifo_ptr - priv->fifo_base) * sizeof(u32);
|
||||
|
||||
/* asking the HV for a blit will kick the FIFO */
|
||||
status = lv1_gpu_context_attribute(priv->context_handle,
|
||||
L1GPU_CONTEXT_ATTRIBUTE_FB_BLIT, 0,
|
||||
0, 0, 0);
|
||||
if (status)
|
||||
dev_err(&dev->core,
|
||||
"%s: lv1_gpu_context_attribute failed %d\n", __func__,
|
||||
status);
|
||||
|
||||
if ((priv->fifo_ptr - priv->fifo_base) * sizeof(u32) >
|
||||
FIFO_SIZE - 1024) {
|
||||
dev_dbg(&dev->core, "FIFO full, rewinding\n");
|
||||
ps3vram_wait_ring(dev, 200);
|
||||
ps3vram_rewind_ring(dev);
|
||||
}
|
||||
|
||||
mutex_unlock(&ps3_gpu_mutex);
|
||||
}
|
||||
|
||||
static void ps3vram_bind(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0, 1);
|
||||
ps3vram_out_ring(priv, 0x31337303);
|
||||
ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x180, 3);
|
||||
ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
|
||||
ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
|
||||
ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
|
||||
|
||||
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0, 1);
|
||||
ps3vram_out_ring(priv, 0x3137c0de);
|
||||
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x180, 3);
|
||||
ps3vram_out_ring(priv, DMA_NOTIFIER_HANDLE_BASE + NOTIFIER);
|
||||
ps3vram_out_ring(priv, 0xfeed0000); /* DMA video RAM instance */
|
||||
ps3vram_out_ring(priv, 0xfeed0001); /* DMA system RAM instance */
|
||||
|
||||
ps3vram_fire_ring(dev);
|
||||
}
|
||||
|
||||
static int ps3vram_upload(struct ps3_system_bus_device *dev,
|
||||
unsigned int src_offset, unsigned int dst_offset,
|
||||
int len, int count)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
ps3vram_begin_ring(priv, UPLOAD_SUBCH,
|
||||
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
|
||||
ps3vram_out_ring(priv, XDR_IOIF + src_offset);
|
||||
ps3vram_out_ring(priv, dst_offset);
|
||||
ps3vram_out_ring(priv, len);
|
||||
ps3vram_out_ring(priv, len);
|
||||
ps3vram_out_ring(priv, len);
|
||||
ps3vram_out_ring(priv, count);
|
||||
ps3vram_out_ring(priv, (1 << 8) | 1);
|
||||
ps3vram_out_ring(priv, 0);
|
||||
|
||||
ps3vram_notifier_reset(dev);
|
||||
ps3vram_begin_ring(priv, UPLOAD_SUBCH,
|
||||
NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
|
||||
ps3vram_out_ring(priv, 0);
|
||||
ps3vram_begin_ring(priv, UPLOAD_SUBCH, 0x100, 1);
|
||||
ps3vram_out_ring(priv, 0);
|
||||
ps3vram_fire_ring(dev);
|
||||
if (ps3vram_notifier_wait(dev, 200) < 0) {
|
||||
dev_warn(&dev->core, "%s: Notifier timeout\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ps3vram_download(struct ps3_system_bus_device *dev,
|
||||
unsigned int src_offset, unsigned int dst_offset,
|
||||
int len, int count)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
|
||||
NV_MEMORY_TO_MEMORY_FORMAT_OFFSET_IN, 8);
|
||||
ps3vram_out_ring(priv, src_offset);
|
||||
ps3vram_out_ring(priv, XDR_IOIF + dst_offset);
|
||||
ps3vram_out_ring(priv, len);
|
||||
ps3vram_out_ring(priv, len);
|
||||
ps3vram_out_ring(priv, len);
|
||||
ps3vram_out_ring(priv, count);
|
||||
ps3vram_out_ring(priv, (1 << 8) | 1);
|
||||
ps3vram_out_ring(priv, 0);
|
||||
|
||||
ps3vram_notifier_reset(dev);
|
||||
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH,
|
||||
NV_MEMORY_TO_MEMORY_FORMAT_NOTIFY, 1);
|
||||
ps3vram_out_ring(priv, 0);
|
||||
ps3vram_begin_ring(priv, DOWNLOAD_SUBCH, 0x100, 1);
|
||||
ps3vram_out_ring(priv, 0);
|
||||
ps3vram_fire_ring(dev);
|
||||
if (ps3vram_notifier_wait(dev, 200) < 0) {
|
||||
dev_warn(&dev->core, "%s: Notifier timeout\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps3vram_cache_evict(struct ps3_system_bus_device *dev, int entry)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
struct ps3vram_cache *cache = &priv->cache;
|
||||
|
||||
if (!(cache->tags[entry].flags & CACHE_PAGE_DIRTY))
|
||||
return;
|
||||
|
||||
dev_dbg(&dev->core, "Flushing %d: 0x%08x\n", entry,
|
||||
cache->tags[entry].address);
|
||||
if (ps3vram_upload(dev, CACHE_OFFSET + entry * cache->page_size,
|
||||
cache->tags[entry].address, DMA_PAGE_SIZE,
|
||||
cache->page_size / DMA_PAGE_SIZE) < 0) {
|
||||
dev_err(&dev->core,
|
||||
"Failed to upload from 0x%x to " "0x%x size 0x%x\n",
|
||||
entry * cache->page_size, cache->tags[entry].address,
|
||||
cache->page_size);
|
||||
}
|
||||
cache->tags[entry].flags &= ~CACHE_PAGE_DIRTY;
|
||||
}
|
||||
|
||||
static void ps3vram_cache_load(struct ps3_system_bus_device *dev, int entry,
|
||||
unsigned int address)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
struct ps3vram_cache *cache = &priv->cache;
|
||||
|
||||
dev_dbg(&dev->core, "Fetching %d: 0x%08x\n", entry, address);
|
||||
if (ps3vram_download(dev, address,
|
||||
CACHE_OFFSET + entry * cache->page_size,
|
||||
DMA_PAGE_SIZE,
|
||||
cache->page_size / DMA_PAGE_SIZE) < 0) {
|
||||
dev_err(&dev->core,
|
||||
"Failed to download from 0x%x to 0x%x size 0x%x\n",
|
||||
address, entry * cache->page_size, cache->page_size);
|
||||
}
|
||||
|
||||
cache->tags[entry].address = address;
|
||||
cache->tags[entry].flags |= CACHE_PAGE_PRESENT;
|
||||
}
|
||||
|
||||
|
||||
static void ps3vram_cache_flush(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
struct ps3vram_cache *cache = &priv->cache;
|
||||
int i;
|
||||
|
||||
dev_dbg(&dev->core, "FLUSH\n");
|
||||
for (i = 0; i < cache->page_count; i++) {
|
||||
ps3vram_cache_evict(dev, i);
|
||||
cache->tags[i].flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int ps3vram_cache_match(struct ps3_system_bus_device *dev,
|
||||
loff_t address)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
struct ps3vram_cache *cache = &priv->cache;
|
||||
unsigned int base;
|
||||
unsigned int offset;
|
||||
int i;
|
||||
static int counter;
|
||||
|
||||
offset = (unsigned int) (address & (cache->page_size - 1));
|
||||
base = (unsigned int) (address - offset);
|
||||
|
||||
/* fully associative check */
|
||||
for (i = 0; i < cache->page_count; i++) {
|
||||
if ((cache->tags[i].flags & CACHE_PAGE_PRESENT) &&
|
||||
cache->tags[i].address == base) {
|
||||
cache->hit++;
|
||||
dev_dbg(&dev->core, "Found entry %d: 0x%08x\n", i,
|
||||
cache->tags[i].address);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
/* choose a random entry */
|
||||
i = (jiffies + (counter++)) % cache->page_count;
|
||||
dev_dbg(&dev->core, "Using entry %d\n", i);
|
||||
|
||||
ps3vram_cache_evict(dev, i);
|
||||
ps3vram_cache_load(dev, i, base);
|
||||
|
||||
cache->miss++;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int ps3vram_cache_init(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
priv->cache.page_count = CACHE_PAGE_COUNT;
|
||||
priv->cache.page_size = CACHE_PAGE_SIZE;
|
||||
priv->cache.tags = kzalloc(sizeof(struct ps3vram_tag) *
|
||||
CACHE_PAGE_COUNT, GFP_KERNEL);
|
||||
if (priv->cache.tags == NULL) {
|
||||
dev_err(&dev->core, "Could not allocate cache tags\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev_info(&dev->core, "Created ram cache: %d entries, %d KiB each\n",
|
||||
CACHE_PAGE_COUNT, CACHE_PAGE_SIZE / 1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ps3vram_cache_cleanup(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
ps3vram_cache_flush(dev);
|
||||
kfree(priv->cache.tags);
|
||||
}
|
||||
|
||||
static int ps3vram_read(struct ps3_system_bus_device *dev, loff_t from,
|
||||
size_t len, size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
unsigned int cached, count;
|
||||
|
||||
dev_dbg(&dev->core, "%s: from=0x%08x len=0x%zx\n", __func__,
|
||||
(unsigned int)from, len);
|
||||
|
||||
if (from >= priv->size)
|
||||
return -EIO;
|
||||
|
||||
if (len > priv->size - from)
|
||||
len = priv->size - from;
|
||||
|
||||
/* Copy from vram to buf */
|
||||
count = len;
|
||||
while (count) {
|
||||
unsigned int offset, avail;
|
||||
unsigned int entry;
|
||||
|
||||
offset = (unsigned int) (from & (priv->cache.page_size - 1));
|
||||
avail = priv->cache.page_size - offset;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
entry = ps3vram_cache_match(dev, from);
|
||||
cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
|
||||
|
||||
dev_dbg(&dev->core, "%s: from=%08x cached=%08x offset=%08x "
|
||||
"avail=%08x count=%08x\n", __func__,
|
||||
(unsigned int)from, cached, offset, avail, count);
|
||||
|
||||
if (avail > count)
|
||||
avail = count;
|
||||
memcpy(buf, priv->xdr_buf + cached, avail);
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
buf += avail;
|
||||
count -= avail;
|
||||
from += avail;
|
||||
}
|
||||
|
||||
*retlen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ps3vram_write(struct ps3_system_bus_device *dev, loff_t to,
|
||||
size_t len, size_t *retlen, const u_char *buf)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
unsigned int cached, count;
|
||||
|
||||
if (to >= priv->size)
|
||||
return -EIO;
|
||||
|
||||
if (len > priv->size - to)
|
||||
len = priv->size - to;
|
||||
|
||||
/* Copy from buf to vram */
|
||||
count = len;
|
||||
while (count) {
|
||||
unsigned int offset, avail;
|
||||
unsigned int entry;
|
||||
|
||||
offset = (unsigned int) (to & (priv->cache.page_size - 1));
|
||||
avail = priv->cache.page_size - offset;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
|
||||
entry = ps3vram_cache_match(dev, to);
|
||||
cached = CACHE_OFFSET + entry * priv->cache.page_size + offset;
|
||||
|
||||
dev_dbg(&dev->core, "%s: to=%08x cached=%08x offset=%08x "
|
||||
"avail=%08x count=%08x\n", __func__, (unsigned int)to,
|
||||
cached, offset, avail, count);
|
||||
|
||||
if (avail > count)
|
||||
avail = count;
|
||||
memcpy(priv->xdr_buf + cached, buf, avail);
|
||||
|
||||
priv->cache.tags[entry].flags |= CACHE_PAGE_DIRTY;
|
||||
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
buf += avail;
|
||||
count -= avail;
|
||||
to += avail;
|
||||
}
|
||||
|
||||
*retlen = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ps3vram_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct ps3vram_priv *priv = m->private;
|
||||
|
||||
seq_printf(m, "hit:%u\nmiss:%u\n", priv->cache.hit, priv->cache.miss);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ps3vram_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, ps3vram_proc_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static const struct file_operations ps3vram_proc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ps3vram_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static void __devinit ps3vram_proc_init(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
struct proc_dir_entry *pde;
|
||||
|
||||
pde = proc_create(DEVICE_NAME, 0444, NULL, &ps3vram_proc_fops);
|
||||
if (!pde) {
|
||||
dev_warn(&dev->core, "failed to create /proc entry\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pde->owner = THIS_MODULE;
|
||||
pde->data = priv;
|
||||
}
|
||||
|
||||
static int ps3vram_make_request(struct request_queue *q, struct bio *bio)
|
||||
{
|
||||
struct ps3_system_bus_device *dev = q->queuedata;
|
||||
int write = bio_data_dir(bio) == WRITE;
|
||||
const char *op = write ? "write" : "read";
|
||||
loff_t offset = bio->bi_sector << 9;
|
||||
int error = 0;
|
||||
struct bio_vec *bvec;
|
||||
unsigned int i;
|
||||
|
||||
dev_dbg(&dev->core, "%s\n", __func__);
|
||||
|
||||
bio_for_each_segment(bvec, bio, i) {
|
||||
/* PS3 is ppc64, so we don't handle highmem */
|
||||
char *ptr = page_address(bvec->bv_page) + bvec->bv_offset;
|
||||
size_t len = bvec->bv_len, retlen;
|
||||
|
||||
dev_dbg(&dev->core, " %s %zu bytes at offset %llu\n", op,
|
||||
len, offset);
|
||||
if (write)
|
||||
error = ps3vram_write(dev, offset, len, &retlen, ptr);
|
||||
else
|
||||
error = ps3vram_read(dev, offset, len, &retlen, ptr);
|
||||
|
||||
if (error) {
|
||||
dev_err(&dev->core, "%s failed\n", op);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (retlen != len) {
|
||||
dev_err(&dev->core, "Short %s\n", op);
|
||||
goto out;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
|
||||
dev_dbg(&dev->core, "%s completed\n", op);
|
||||
|
||||
out:
|
||||
bio_endio(bio, error);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit ps3vram_probe(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv;
|
||||
int error, status;
|
||||
struct request_queue *queue;
|
||||
struct gendisk *gendisk;
|
||||
u64 ddr_lpar, ctrl_lpar, info_lpar, reports_lpar, ddr_size,
|
||||
reports_size;
|
||||
char *rest;
|
||||
|
||||
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
error = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
dev->core.driver_data = priv;
|
||||
|
||||
priv = dev->core.driver_data;
|
||||
|
||||
/* Allocate XDR buffer (1MiB aligned) */
|
||||
priv->xdr_buf = (void *)__get_free_pages(GFP_KERNEL,
|
||||
get_order(XDR_BUF_SIZE));
|
||||
if (priv->xdr_buf == NULL) {
|
||||
dev_err(&dev->core, "Could not allocate XDR buffer\n");
|
||||
error = -ENOMEM;
|
||||
goto fail_free_priv;
|
||||
}
|
||||
|
||||
/* Put FIFO at begginning of XDR buffer */
|
||||
priv->fifo_base = (u32 *) (priv->xdr_buf + FIFO_OFFSET);
|
||||
priv->fifo_ptr = priv->fifo_base;
|
||||
|
||||
/* XXX: Need to open GPU, in case ps3fb or snd_ps3 aren't loaded */
|
||||
if (ps3_open_hv_device(dev)) {
|
||||
dev_err(&dev->core, "ps3_open_hv_device failed\n");
|
||||
error = -EAGAIN;
|
||||
goto out_close_gpu;
|
||||
}
|
||||
|
||||
/* Request memory */
|
||||
status = -1;
|
||||
ddr_size = ALIGN(memparse(size, &rest), 1024*1024);
|
||||
if (!ddr_size) {
|
||||
dev_err(&dev->core, "Specified size is too small\n");
|
||||
error = -EINVAL;
|
||||
goto out_close_gpu;
|
||||
}
|
||||
|
||||
while (ddr_size > 0) {
|
||||
status = lv1_gpu_memory_allocate(ddr_size, 0, 0, 0, 0,
|
||||
&priv->memory_handle,
|
||||
&ddr_lpar);
|
||||
if (!status)
|
||||
break;
|
||||
ddr_size -= 1024*1024;
|
||||
}
|
||||
if (status) {
|
||||
dev_err(&dev->core, "lv1_gpu_memory_allocate failed %d\n",
|
||||
status);
|
||||
error = -ENOMEM;
|
||||
goto out_free_xdr_buf;
|
||||
}
|
||||
|
||||
/* Request context */
|
||||
status = lv1_gpu_context_allocate(priv->memory_handle, 0,
|
||||
&priv->context_handle, &ctrl_lpar,
|
||||
&info_lpar, &reports_lpar,
|
||||
&reports_size);
|
||||
if (status) {
|
||||
dev_err(&dev->core, "lv1_gpu_context_allocate failed %d\n",
|
||||
status);
|
||||
error = -ENOMEM;
|
||||
goto out_free_memory;
|
||||
}
|
||||
|
||||
/* Map XDR buffer to RSX */
|
||||
status = lv1_gpu_context_iomap(priv->context_handle, XDR_IOIF,
|
||||
ps3_mm_phys_to_lpar(__pa(priv->xdr_buf)),
|
||||
XDR_BUF_SIZE, 0);
|
||||
if (status) {
|
||||
dev_err(&dev->core, "lv1_gpu_context_iomap failed %d\n",
|
||||
status);
|
||||
error = -ENOMEM;
|
||||
goto out_free_context;
|
||||
}
|
||||
|
||||
priv->ddr_base = ioremap_flags(ddr_lpar, ddr_size, _PAGE_NO_CACHE);
|
||||
|
||||
if (!priv->ddr_base) {
|
||||
dev_err(&dev->core, "ioremap DDR failed\n");
|
||||
error = -ENOMEM;
|
||||
goto out_free_context;
|
||||
}
|
||||
|
||||
priv->ctrl = ioremap(ctrl_lpar, 64 * 1024);
|
||||
if (!priv->ctrl) {
|
||||
dev_err(&dev->core, "ioremap CTRL failed\n");
|
||||
error = -ENOMEM;
|
||||
goto out_unmap_vram;
|
||||
}
|
||||
|
||||
priv->reports = ioremap(reports_lpar, reports_size);
|
||||
if (!priv->reports) {
|
||||
dev_err(&dev->core, "ioremap REPORTS failed\n");
|
||||
error = -ENOMEM;
|
||||
goto out_unmap_ctrl;
|
||||
}
|
||||
|
||||
mutex_lock(&ps3_gpu_mutex);
|
||||
ps3vram_init_ring(dev);
|
||||
mutex_unlock(&ps3_gpu_mutex);
|
||||
|
||||
priv->size = ddr_size;
|
||||
|
||||
ps3vram_bind(dev);
|
||||
|
||||
mutex_lock(&ps3_gpu_mutex);
|
||||
error = ps3vram_wait_ring(dev, 100);
|
||||
mutex_unlock(&ps3_gpu_mutex);
|
||||
if (error < 0) {
|
||||
dev_err(&dev->core, "Failed to initialize channels\n");
|
||||
error = -ETIMEDOUT;
|
||||
goto out_unmap_reports;
|
||||
}
|
||||
|
||||
ps3vram_cache_init(dev);
|
||||
ps3vram_proc_init(dev);
|
||||
|
||||
queue = blk_alloc_queue(GFP_KERNEL);
|
||||
if (!queue) {
|
||||
dev_err(&dev->core, "blk_alloc_queue failed\n");
|
||||
error = -ENOMEM;
|
||||
goto out_cache_cleanup;
|
||||
}
|
||||
|
||||
priv->queue = queue;
|
||||
queue->queuedata = dev;
|
||||
blk_queue_make_request(queue, ps3vram_make_request);
|
||||
blk_queue_max_phys_segments(queue, MAX_PHYS_SEGMENTS);
|
||||
blk_queue_max_hw_segments(queue, MAX_HW_SEGMENTS);
|
||||
blk_queue_max_segment_size(queue, MAX_SEGMENT_SIZE);
|
||||
blk_queue_max_sectors(queue, SAFE_MAX_SECTORS);
|
||||
|
||||
gendisk = alloc_disk(1);
|
||||
if (!gendisk) {
|
||||
dev_err(&dev->core, "alloc_disk failed\n");
|
||||
error = -ENOMEM;
|
||||
goto fail_cleanup_queue;
|
||||
}
|
||||
|
||||
priv->gendisk = gendisk;
|
||||
gendisk->major = ps3vram_major;
|
||||
gendisk->first_minor = 0;
|
||||
gendisk->fops = &ps3vram_fops;
|
||||
gendisk->queue = queue;
|
||||
gendisk->private_data = dev;
|
||||
gendisk->driverfs_dev = &dev->core;
|
||||
strlcpy(gendisk->disk_name, DEVICE_NAME, sizeof(gendisk->disk_name));
|
||||
set_capacity(gendisk, priv->size >> 9);
|
||||
|
||||
dev_info(&dev->core, "%s: Using %lu MiB of GPU memory\n",
|
||||
gendisk->disk_name, get_capacity(gendisk) >> 11);
|
||||
|
||||
add_disk(gendisk);
|
||||
return 0;
|
||||
|
||||
fail_cleanup_queue:
|
||||
blk_cleanup_queue(queue);
|
||||
out_cache_cleanup:
|
||||
remove_proc_entry(DEVICE_NAME, NULL);
|
||||
ps3vram_cache_cleanup(dev);
|
||||
out_unmap_reports:
|
||||
iounmap(priv->reports);
|
||||
out_unmap_ctrl:
|
||||
iounmap(priv->ctrl);
|
||||
out_unmap_vram:
|
||||
iounmap(priv->ddr_base);
|
||||
out_free_context:
|
||||
lv1_gpu_context_free(priv->context_handle);
|
||||
out_free_memory:
|
||||
lv1_gpu_memory_free(priv->memory_handle);
|
||||
out_close_gpu:
|
||||
ps3_close_hv_device(dev);
|
||||
out_free_xdr_buf:
|
||||
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
||||
fail_free_priv:
|
||||
kfree(priv);
|
||||
dev->core.driver_data = NULL;
|
||||
fail:
|
||||
return error;
|
||||
}
|
||||
|
||||
static int ps3vram_remove(struct ps3_system_bus_device *dev)
|
||||
{
|
||||
struct ps3vram_priv *priv = dev->core.driver_data;
|
||||
|
||||
del_gendisk(priv->gendisk);
|
||||
put_disk(priv->gendisk);
|
||||
blk_cleanup_queue(priv->queue);
|
||||
remove_proc_entry(DEVICE_NAME, NULL);
|
||||
ps3vram_cache_cleanup(dev);
|
||||
iounmap(priv->reports);
|
||||
iounmap(priv->ctrl);
|
||||
iounmap(priv->ddr_base);
|
||||
lv1_gpu_context_free(priv->context_handle);
|
||||
lv1_gpu_memory_free(priv->memory_handle);
|
||||
ps3_close_hv_device(dev);
|
||||
free_pages((unsigned long) priv->xdr_buf, get_order(XDR_BUF_SIZE));
|
||||
kfree(priv);
|
||||
dev->core.driver_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ps3_system_bus_driver ps3vram = {
|
||||
.match_id = PS3_MATCH_ID_GPU,
|
||||
.match_sub_id = PS3_MATCH_SUB_ID_GPU_RAMDISK,
|
||||
.core.name = DEVICE_NAME,
|
||||
.core.owner = THIS_MODULE,
|
||||
.probe = ps3vram_probe,
|
||||
.remove = ps3vram_remove,
|
||||
.shutdown = ps3vram_remove,
|
||||
};
|
||||
|
||||
|
||||
static int __init ps3vram_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
|
||||
return -ENODEV;
|
||||
|
||||
error = register_blkdev(0, DEVICE_NAME);
|
||||
if (error <= 0) {
|
||||
pr_err("%s: register_blkdev failed %d\n", DEVICE_NAME, error);
|
||||
return error;
|
||||
}
|
||||
ps3vram_major = error;
|
||||
|
||||
pr_info("%s: registered block device major %d\n", DEVICE_NAME,
|
||||
ps3vram_major);
|
||||
|
||||
error = ps3_system_bus_driver_register(&ps3vram);
|
||||
if (error)
|
||||
unregister_blkdev(ps3vram_major, DEVICE_NAME);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit ps3vram_exit(void)
|
||||
{
|
||||
ps3_system_bus_driver_unregister(&ps3vram);
|
||||
unregister_blkdev(ps3vram_major, DEVICE_NAME);
|
||||
}
|
||||
|
||||
module_init(ps3vram_init);
|
||||
module_exit(ps3vram_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("PS3 Video RAM Storage Driver");
|
||||
MODULE_AUTHOR("Sony Corporation");
|
||||
MODULE_ALIAS(PS3_MODULE_ALIAS_GPU_RAMDISK);
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/hdreg.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#include <xen/xenbus.h>
|
||||
#include <xen/grant_table.h>
|
||||
|
|
@ -82,6 +83,7 @@ struct blkfront_info
|
|||
enum blkif_state connected;
|
||||
int ring_ref;
|
||||
struct blkif_front_ring ring;
|
||||
struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
|
||||
unsigned int evtchn, irq;
|
||||
struct request_queue *rq;
|
||||
struct work_struct work;
|
||||
|
|
@ -204,12 +206,11 @@ static int blkif_queue_request(struct request *req)
|
|||
struct blkfront_info *info = req->rq_disk->private_data;
|
||||
unsigned long buffer_mfn;
|
||||
struct blkif_request *ring_req;
|
||||
struct req_iterator iter;
|
||||
struct bio_vec *bvec;
|
||||
unsigned long id;
|
||||
unsigned int fsect, lsect;
|
||||
int ref;
|
||||
int i, ref;
|
||||
grant_ref_t gref_head;
|
||||
struct scatterlist *sg;
|
||||
|
||||
if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
|
||||
return 1;
|
||||
|
|
@ -238,12 +239,13 @@ static int blkif_queue_request(struct request *req)
|
|||
if (blk_barrier_rq(req))
|
||||
ring_req->operation = BLKIF_OP_WRITE_BARRIER;
|
||||
|
||||
ring_req->nr_segments = 0;
|
||||
rq_for_each_segment(bvec, req, iter) {
|
||||
BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
||||
buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
|
||||
fsect = bvec->bv_offset >> 9;
|
||||
lsect = fsect + (bvec->bv_len >> 9) - 1;
|
||||
ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
|
||||
BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
||||
|
||||
for_each_sg(info->sg, sg, ring_req->nr_segments, i) {
|
||||
buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg)));
|
||||
fsect = sg->offset >> 9;
|
||||
lsect = fsect + (sg->length >> 9) - 1;
|
||||
/* install a grant reference. */
|
||||
ref = gnttab_claim_grant_reference(&gref_head);
|
||||
BUG_ON(ref == -ENOSPC);
|
||||
|
|
@ -254,16 +256,12 @@ static int blkif_queue_request(struct request *req)
|
|||
buffer_mfn,
|
||||
rq_data_dir(req) );
|
||||
|
||||
info->shadow[id].frame[ring_req->nr_segments] =
|
||||
mfn_to_pfn(buffer_mfn);
|
||||
|
||||
ring_req->seg[ring_req->nr_segments] =
|
||||
info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
|
||||
ring_req->seg[i] =
|
||||
(struct blkif_request_segment) {
|
||||
.gref = ref,
|
||||
.first_sect = fsect,
|
||||
.last_sect = lsect };
|
||||
|
||||
ring_req->nr_segments++;
|
||||
}
|
||||
|
||||
info->ring.req_prod_pvt++;
|
||||
|
|
@ -622,6 +620,8 @@ static int setup_blkring(struct xenbus_device *dev,
|
|||
SHARED_RING_INIT(sring);
|
||||
FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
|
||||
|
||||
sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
|
||||
|
||||
err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
|
||||
if (err < 0) {
|
||||
free_page((unsigned long)sring);
|
||||
|
|
@ -977,6 +977,8 @@ static void backend_changed(struct xenbus_device *dev,
|
|||
break;
|
||||
|
||||
case XenbusStateClosing:
|
||||
if (info->gd == NULL)
|
||||
xenbus_dev_fatal(dev, -ENODEV, "gd is NULL");
|
||||
bd = bdget_disk(info->gd, 0);
|
||||
if (bd == NULL)
|
||||
xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
|
||||
|
|
|
|||
|
|
@ -489,6 +489,28 @@ static void ace_fsm_dostate(struct ace_device *ace)
|
|||
ace->fsm_state, ace->id_req_count);
|
||||
#endif
|
||||
|
||||
/* Verify that there is actually a CF in the slot. If not, then
|
||||
* bail out back to the idle state and wake up all the waiters */
|
||||
status = ace_in32(ace, ACE_STATUS);
|
||||
if ((status & ACE_STATUS_CFDETECT) == 0) {
|
||||
ace->fsm_state = ACE_FSM_STATE_IDLE;
|
||||
ace->media_change = 1;
|
||||
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 back to IDLE state and notify waiters */
|
||||
ace->fsm_state = ACE_FSM_STATE_IDLE;
|
||||
ace->id_result = -EIO;
|
||||
while (ace->id_req_count) {
|
||||
complete(&ace->id_completion);
|
||||
ace->id_req_count--;
|
||||
}
|
||||
}
|
||||
|
||||
switch (ace->fsm_state) {
|
||||
case ACE_FSM_STATE_IDLE:
|
||||
/* See if there is anything to do */
|
||||
|
|
|
|||
|
|
@ -271,15 +271,15 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
|
|||
nb_order = (nb_order >> 1) & 7;
|
||||
pci_read_config_dword(nb, AMD64_GARTAPERTUREBASE, &nb_base);
|
||||
nb_aper = nb_base << 25;
|
||||
if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Northbridge seems to contain crap. Try the AGP bridge. */
|
||||
|
||||
pci_read_config_word(agp, cap+0x14, &apsize);
|
||||
if (apsize == 0xffff)
|
||||
if (apsize == 0xffff) {
|
||||
if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order))
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
apsize &= 0xfff;
|
||||
/* Some BIOS use weird encodings not in the AGPv3 table. */
|
||||
|
|
@ -301,6 +301,11 @@ static __devinit int fix_northbridge(struct pci_dev *nb, struct pci_dev *agp,
|
|||
order = nb_order;
|
||||
}
|
||||
|
||||
if (nb_order >= order) {
|
||||
if (agp_aperture_valid(nb_aper, (32*1024*1024)<<nb_order))
|
||||
return 0;
|
||||
}
|
||||
|
||||
dev_info(&agp->dev, "aperture from AGP @ %Lx size %u MB\n",
|
||||
aper, 32 << order);
|
||||
if (order < 0 || !agp_aperture_valid(aper, (32*1024*1024)<<order))
|
||||
|
|
|
|||
|
|
@ -633,13 +633,15 @@ static void intel_i830_init_gtt_entries(void)
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (gtt_entries > 0)
|
||||
if (gtt_entries > 0) {
|
||||
dev_info(&agp_bridge->dev->dev, "detected %dK %s memory\n",
|
||||
gtt_entries / KB(1), local ? "local" : "stolen");
|
||||
else
|
||||
gtt_entries /= KB(4);
|
||||
} else {
|
||||
dev_info(&agp_bridge->dev->dev,
|
||||
"no pre-allocated video memory detected\n");
|
||||
gtt_entries /= KB(4);
|
||||
gtt_entries = 0;
|
||||
}
|
||||
|
||||
intel_private.gtt_entries = gtt_entries;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -359,9 +359,16 @@ fail:
|
|||
return error;
|
||||
}
|
||||
|
||||
static struct device *next_device(struct klist_iter *i) {
|
||||
struct klist_node * n = klist_next(i);
|
||||
return n ? container_of(n, struct device, knode_parent) : NULL;
|
||||
static int
|
||||
find_quicksilver(struct device *dev, void *data)
|
||||
{
|
||||
struct parisc_device **lba = data;
|
||||
struct parisc_device *padev = to_parisc_device(dev);
|
||||
|
||||
if (IS_QUICKSILVER(padev))
|
||||
*lba = padev;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -372,8 +379,6 @@ parisc_agp_init(void)
|
|||
int err = -1;
|
||||
struct parisc_device *sba = NULL, *lba = NULL;
|
||||
struct lba_device *lbadev = NULL;
|
||||
struct device *dev = NULL;
|
||||
struct klist_iter i;
|
||||
|
||||
if (!sba_list)
|
||||
goto out;
|
||||
|
|
@ -386,13 +391,7 @@ parisc_agp_init(void)
|
|||
}
|
||||
|
||||
/* Now search our Pluto for our precious AGP device... */
|
||||
klist_iter_init(&sba->dev.klist_children, &i);
|
||||
while ((dev = next_device(&i))) {
|
||||
struct parisc_device *padev = to_parisc_device(dev);
|
||||
if (IS_QUICKSILVER(padev))
|
||||
lba = padev;
|
||||
}
|
||||
klist_iter_exit(&i);
|
||||
device_for_each_child(&sba->dev, &lba, find_quicksilver);
|
||||
|
||||
if (!lba) {
|
||||
printk(KERN_INFO DRVPFX "No AGP devices found.\n");
|
||||
|
|
|
|||
|
|
@ -1139,15 +1139,6 @@ static int hvcs_open(struct tty_struct *tty, struct file *filp)
|
|||
hvcsd->tty = tty;
|
||||
tty->driver_data = hvcsd;
|
||||
|
||||
/*
|
||||
* Set this driver to low latency so that we actually have a chance at
|
||||
* catching a throttled TTY after we flip_buffer_push. Otherwise the
|
||||
* flush_to_async may not execute until after the kernel_thread has
|
||||
* yielded and resumed the next flip_buffer_push resulting in data
|
||||
* loss.
|
||||
*/
|
||||
tty->low_latency = 1;
|
||||
|
||||
memset(&hvcsd->buffer[0], 0x00, HVCS_BUFF_LEN);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -810,7 +810,6 @@ static int hvsi_open(struct tty_struct *tty, struct file *filp)
|
|||
hp = &hvsi_ports[line];
|
||||
|
||||
tty->driver_data = hp;
|
||||
tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */
|
||||
|
||||
mb();
|
||||
if (hp->state == HVSI_FSP_DIED)
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ struct scc_port {
|
|||
/* The SCC needs 3.5 PCLK cycles recovery time between to register
|
||||
* accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 *
|
||||
* 125 ns = 437.5 ns. This is too short for udelay().
|
||||
* 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be
|
||||
* 10/16/95: A tstb st_mfp.par_dt_reg takes 600ns (sure?) and thus should be
|
||||
* quite right
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1746,9 +1746,10 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
|
|||
sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %ld\n", rc);
|
||||
break;
|
||||
case SXIO_DO_RAMTEST:
|
||||
if (sx_initialized) /* Already initialized: better not ramtest the board. */
|
||||
if (sx_initialized) { /* Already initialized: better not ramtest the board. */
|
||||
rc = -EPERM;
|
||||
break;
|
||||
}
|
||||
if (IS_SX_BOARD(board)) {
|
||||
rc = do_memtest(board, 0, 0x7000);
|
||||
if (!rc)
|
||||
|
|
@ -1788,7 +1789,7 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
|
|||
nbytes - i : SX_CHUNK_SIZE)) {
|
||||
kfree(tmp);
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
goto out;
|
||||
}
|
||||
memcpy_toio(board->base2 + offset + i, tmp,
|
||||
(i + SX_CHUNK_SIZE > nbytes) ?
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* SLD 9630 TT 1.1 and SLB 9635 TT 1.2 Trusted Platform Module
|
||||
* Specifications at www.trustedcomputinggroup.org
|
||||
*
|
||||
* Copyright (C) 2005, Marcel Selhorst <selhorst@crypto.rub.de>
|
||||
* Copyright (C) 2005, Marcel Selhorst <m.selhorst@sirrix.com>
|
||||
* Sirrix AG - security technologies, http://www.sirrix.com and
|
||||
* Applied Data Security Group, Ruhr-University Bochum, Germany
|
||||
* Project-Homepage: http://www.prosec.rub.de/tpm
|
||||
|
|
@ -636,7 +636,7 @@ static void __exit cleanup_inf(void)
|
|||
module_init(init_inf);
|
||||
module_exit(cleanup_inf);
|
||||
|
||||
MODULE_AUTHOR("Marcel Selhorst <[email protected]>");
|
||||
MODULE_AUTHOR("Marcel Selhorst <[email protected]>");
|
||||
MODULE_DESCRIPTION("Driver for Infineon TPM SLD 9630 TT 1.1 / SLB 9635 TT 1.2");
|
||||
MODULE_VERSION("1.9");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -754,11 +754,6 @@ static struct kobj_type ktype_cpufreq = {
|
|||
.release = cpufreq_sysfs_release,
|
||||
};
|
||||
|
||||
static struct kobj_type ktype_empty_cpufreq = {
|
||||
.sysfs_ops = &sysfs_ops,
|
||||
.release = cpufreq_sysfs_release,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* cpufreq_add_dev - add a CPU device
|
||||
|
|
@ -892,36 +887,26 @@ static int cpufreq_add_dev(struct sys_device *sys_dev)
|
|||
memcpy(&new_policy, policy, sizeof(struct cpufreq_policy));
|
||||
|
||||
/* prepare interface data */
|
||||
if (!cpufreq_driver->hide_interface) {
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
|
||||
&sys_dev->kobj, "cpufreq");
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq, &sys_dev->kobj,
|
||||
"cpufreq");
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
|
||||
/* set up files for this cpu device */
|
||||
drv_attr = cpufreq_driver->attr;
|
||||
while ((drv_attr) && (*drv_attr)) {
|
||||
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
|
||||
/* set up files for this cpu device */
|
||||
drv_attr = cpufreq_driver->attr;
|
||||
while ((drv_attr) && (*drv_attr)) {
|
||||
ret = sysfs_create_file(&policy->kobj,
|
||||
&((*drv_attr)->attr));
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
drv_attr++;
|
||||
}
|
||||
if (cpufreq_driver->get) {
|
||||
ret = sysfs_create_file(&policy->kobj,
|
||||
&cpuinfo_cur_freq.attr);
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
}
|
||||
if (cpufreq_driver->target) {
|
||||
ret = sysfs_create_file(&policy->kobj,
|
||||
&scaling_cur_freq.attr);
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
}
|
||||
} else {
|
||||
ret = kobject_init_and_add(&policy->kobj, &ktype_empty_cpufreq,
|
||||
&sys_dev->kobj, "cpufreq");
|
||||
drv_attr++;
|
||||
}
|
||||
if (cpufreq_driver->get) {
|
||||
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
}
|
||||
if (cpufreq_driver->target) {
|
||||
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
|
||||
if (ret)
|
||||
goto err_out_driver_exit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -457,10 +457,12 @@ static int init_ixp_crypto(void)
|
|||
if (!ctx_pool) {
|
||||
goto err;
|
||||
}
|
||||
ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0);
|
||||
ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0,
|
||||
"ixp_crypto:out", NULL);
|
||||
if (ret)
|
||||
goto err;
|
||||
ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0);
|
||||
ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0,
|
||||
"ixp_crypto:in", NULL);
|
||||
if (ret) {
|
||||
qmgr_release_queue(SEND_QID);
|
||||
goto err;
|
||||
|
|
|
|||
|
|
@ -489,4 +489,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michal Ludvig");
|
||||
|
||||
MODULE_ALIAS("aes");
|
||||
MODULE_ALIAS("aes-all");
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
|
|||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Michal Ludvig");
|
||||
|
||||
MODULE_ALIAS("sha1");
|
||||
MODULE_ALIAS("sha256");
|
||||
MODULE_ALIAS("sha1-all");
|
||||
MODULE_ALIAS("sha256-all");
|
||||
MODULE_ALIAS("sha1-padlock");
|
||||
MODULE_ALIAS("sha256-padlock");
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -518,6 +518,7 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
|
|||
dma_chan_name(chan), err);
|
||||
else
|
||||
break;
|
||||
chan->private = NULL;
|
||||
chan = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -536,6 +537,7 @@ void dma_release_channel(struct dma_chan *chan)
|
|||
WARN_ONCE(chan->client_count != 1,
|
||||
"chan reference count %d != 1\n", chan->client_count);
|
||||
dma_chan_put(chan);
|
||||
chan->private = NULL;
|
||||
mutex_unlock(&dma_list_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dma_release_channel);
|
||||
|
|
|
|||
|
|
@ -430,13 +430,15 @@ late_initcall(dmatest_init);
|
|||
static void __exit dmatest_exit(void)
|
||||
{
|
||||
struct dmatest_chan *dtc, *_dtc;
|
||||
struct dma_chan *chan;
|
||||
|
||||
list_for_each_entry_safe(dtc, _dtc, &dmatest_channels, node) {
|
||||
list_del(&dtc->node);
|
||||
chan = dtc->chan;
|
||||
dmatest_cleanup_channel(dtc);
|
||||
pr_debug("dmatest: dropped channel %s\n",
|
||||
dma_chan_name(dtc->chan));
|
||||
dma_release_channel(dtc->chan);
|
||||
dma_chan_name(chan));
|
||||
dma_release_channel(chan);
|
||||
}
|
||||
}
|
||||
module_exit(dmatest_exit);
|
||||
|
|
|
|||
|
|
@ -560,7 +560,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
|
|||
unsigned long flags)
|
||||
{
|
||||
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
|
||||
struct dw_dma_slave *dws = dwc->dws;
|
||||
struct dw_dma_slave *dws = chan->private;
|
||||
struct dw_desc *prev;
|
||||
struct dw_desc *first;
|
||||
u32 ctllo;
|
||||
|
|
@ -790,7 +790,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
|
|||
cfghi = DWC_CFGH_FIFO_MODE;
|
||||
cfglo = 0;
|
||||
|
||||
dws = dwc->dws;
|
||||
dws = chan->private;
|
||||
if (dws) {
|
||||
/*
|
||||
* We need controller-specific data to set up slave
|
||||
|
|
@ -866,7 +866,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
|
|||
spin_lock_bh(&dwc->lock);
|
||||
list_splice_init(&dwc->free_list, &list);
|
||||
dwc->descs_allocated = 0;
|
||||
dwc->dws = NULL;
|
||||
|
||||
/* Disable interrupts */
|
||||
channel_clear_bit(dw, MASK.XFER, dwc->mask);
|
||||
|
|
|
|||
|
|
@ -139,8 +139,6 @@ struct dw_dma_chan {
|
|||
struct list_head queue;
|
||||
struct list_head free_list;
|
||||
|
||||
struct dw_dma_slave *dws;
|
||||
|
||||
unsigned int descs_allocated;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,8 @@ static void dma_start(struct fsl_dma_chan *fsl_chan)
|
|||
|
||||
static void dma_halt(struct fsl_dma_chan *fsl_chan)
|
||||
{
|
||||
int i = 0;
|
||||
int i;
|
||||
|
||||
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr,
|
||||
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) | FSL_DMA_MR_CA,
|
||||
32);
|
||||
|
|
@ -166,8 +167,11 @@ static void dma_halt(struct fsl_dma_chan *fsl_chan)
|
|||
DMA_IN(fsl_chan, &fsl_chan->reg_base->mr, 32) & ~(FSL_DMA_MR_CS
|
||||
| FSL_DMA_MR_EMS_EN | FSL_DMA_MR_CA), 32);
|
||||
|
||||
while (!dma_is_idle(fsl_chan) && (i++ < 100))
|
||||
for (i = 0; i < 100; i++) {
|
||||
if (dma_is_idle(fsl_chan))
|
||||
break;
|
||||
udelay(10);
|
||||
}
|
||||
if (i >= 100 && !dma_is_idle(fsl_chan))
|
||||
dev_err(fsl_chan->dev, "DMA halt timeout!\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2007 Intel Corporation.
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2007 Intel Corporation.
|
||||
* Copyright(c) 2007 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
@ -49,6 +49,23 @@
|
|||
|
||||
#define DCA_TAG_MAP_MASK 0xDF
|
||||
|
||||
/* expected tag map bytes for I/OAT ver.2 */
|
||||
#define DCA2_TAG_MAP_BYTE0 0x80
|
||||
#define DCA2_TAG_MAP_BYTE1 0x0
|
||||
#define DCA2_TAG_MAP_BYTE2 0x81
|
||||
#define DCA2_TAG_MAP_BYTE3 0x82
|
||||
#define DCA2_TAG_MAP_BYTE4 0x82
|
||||
|
||||
/* verify if tag map matches expected values */
|
||||
static inline int dca2_tag_map_valid(u8 *tag_map)
|
||||
{
|
||||
return ((tag_map[0] == DCA2_TAG_MAP_BYTE0) &&
|
||||
(tag_map[1] == DCA2_TAG_MAP_BYTE1) &&
|
||||
(tag_map[2] == DCA2_TAG_MAP_BYTE2) &&
|
||||
(tag_map[3] == DCA2_TAG_MAP_BYTE3) &&
|
||||
(tag_map[4] == DCA2_TAG_MAP_BYTE4));
|
||||
}
|
||||
|
||||
/*
|
||||
* "Legacy" DCA systems do not implement the DCA register set in the
|
||||
* I/OAT device. Software needs direct support for their tag mappings.
|
||||
|
|
@ -452,6 +469,13 @@ struct dca_provider *ioat2_dca_init(struct pci_dev *pdev, void __iomem *iobase)
|
|||
ioatdca->tag_map[i] = 0;
|
||||
}
|
||||
|
||||
if (!dca2_tag_map_valid(ioatdca->tag_map)) {
|
||||
dev_err(&pdev->dev, "APICID_TAG_MAP set incorrectly by BIOS, "
|
||||
"disabling DCA\n");
|
||||
free_dca_provider(dca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = register_dca_provider(dca, &pdev->dev);
|
||||
if (err) {
|
||||
free_dca_provider(dca);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* Intel I/OAT DMA Linux driver
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
@ -189,11 +189,13 @@ static int ioat_dma_enumerate_channels(struct ioatdma_device *device)
|
|||
ioat_chan->xfercap = xfercap;
|
||||
ioat_chan->desccount = 0;
|
||||
INIT_DELAYED_WORK(&ioat_chan->work, ioat_dma_chan_reset_part2);
|
||||
if (ioat_chan->device->version != IOAT_VER_1_2) {
|
||||
writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE
|
||||
| IOAT_DMA_DCA_ANY_CPU,
|
||||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
}
|
||||
if (ioat_chan->device->version == IOAT_VER_2_0)
|
||||
writel(IOAT_DCACTRL_CMPL_WRITE_ENABLE |
|
||||
IOAT_DMA_DCA_ANY_CPU,
|
||||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
else if (ioat_chan->device->version == IOAT_VER_3_0)
|
||||
writel(IOAT_DMA_DCA_ANY_CPU,
|
||||
ioat_chan->reg_base + IOAT_DCACTRL_OFFSET);
|
||||
spin_lock_init(&ioat_chan->cleanup_lock);
|
||||
spin_lock_init(&ioat_chan->desc_lock);
|
||||
INIT_LIST_HEAD(&ioat_chan->free_desc);
|
||||
|
|
@ -1169,9 +1171,8 @@ static void ioat_dma_memcpy_cleanup(struct ioat_dma_chan *ioat_chan)
|
|||
* up if the client is done with the descriptor
|
||||
*/
|
||||
if (async_tx_test_ack(&desc->async_tx)) {
|
||||
list_del(&desc->node);
|
||||
list_add_tail(&desc->node,
|
||||
&ioat_chan->free_desc);
|
||||
list_move_tail(&desc->node,
|
||||
&ioat_chan->free_desc);
|
||||
} else
|
||||
desc->async_tx.cookie = 0;
|
||||
} else {
|
||||
|
|
@ -1362,6 +1363,7 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
|
|||
dma_cookie_t cookie;
|
||||
int err = 0;
|
||||
struct completion cmp;
|
||||
unsigned long tmo;
|
||||
|
||||
src = kzalloc(sizeof(u8) * IOAT_TEST_SIZE, GFP_KERNEL);
|
||||
if (!src)
|
||||
|
|
@ -1413,9 +1415,10 @@ static int ioat_dma_self_test(struct ioatdma_device *device)
|
|||
}
|
||||
device->common.device_issue_pending(dma_chan);
|
||||
|
||||
wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
|
||||
tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
|
||||
|
||||
if (device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL)
|
||||
if (tmo == 0 ||
|
||||
device->common.device_is_tx_complete(dma_chan, cookie, NULL, NULL)
|
||||
!= DMA_SUCCESS) {
|
||||
dev_err(&device->pdev->dev,
|
||||
"Self-test copy timed out, disabling\n");
|
||||
|
|
@ -1657,6 +1660,13 @@ struct ioatdma_device *ioat_dma_probe(struct pci_dev *pdev,
|
|||
" %d channels, device version 0x%02x, driver version %s\n",
|
||||
device->common.chancnt, device->version, IOAT_DMA_VERSION);
|
||||
|
||||
if (!device->common.chancnt) {
|
||||
dev_err(&device->pdev->dev,
|
||||
"Intel(R) I/OAT DMA Engine problem found: "
|
||||
"zero channels detected\n");
|
||||
goto err_setup_interrupts;
|
||||
}
|
||||
|
||||
err = ioat_dma_setup_interrupts(device);
|
||||
if (err)
|
||||
goto err_setup_interrupts;
|
||||
|
|
@ -1696,6 +1706,9 @@ void ioat_dma_remove(struct ioatdma_device *device)
|
|||
struct dma_chan *chan, *_chan;
|
||||
struct ioat_dma_chan *ioat_chan;
|
||||
|
||||
if (device->version != IOAT_VER_3_0)
|
||||
cancel_delayed_work(&device->work);
|
||||
|
||||
ioat_dma_remove_interrupts(device);
|
||||
|
||||
dma_async_device_unregister(&device->common);
|
||||
|
|
@ -1707,10 +1720,6 @@ void ioat_dma_remove(struct ioatdma_device *device)
|
|||
pci_release_regions(device->pdev);
|
||||
pci_disable_device(device->pdev);
|
||||
|
||||
if (device->version != IOAT_VER_3_0) {
|
||||
cancel_delayed_work(&device->work);
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(chan, _chan,
|
||||
&device->common.channels, device_node) {
|
||||
ioat_chan = to_ioat_chan(chan);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
#include <linux/pci_ids.h>
|
||||
#include <net/tcp.h>
|
||||
|
||||
#define IOAT_DMA_VERSION "3.30"
|
||||
#define IOAT_DMA_VERSION "3.64"
|
||||
|
||||
enum ioat_interrupt {
|
||||
none = 0,
|
||||
|
|
@ -135,12 +135,14 @@ static inline void ioat_set_tcp_copy_break(struct ioatdma_device *dev)
|
|||
#ifdef CONFIG_NET_DMA
|
||||
switch (dev->version) {
|
||||
case IOAT_VER_1_2:
|
||||
case IOAT_VER_3_0:
|
||||
sysctl_tcp_dma_copybreak = 4096;
|
||||
break;
|
||||
case IOAT_VER_2_0:
|
||||
sysctl_tcp_dma_copybreak = 2048;
|
||||
break;
|
||||
case IOAT_VER_3_0:
|
||||
sysctl_tcp_dma_copybreak = 262144;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright(c) 2004 - 2007 Intel Corporation. All rights reserved.
|
||||
* Copyright(c) 2004 - 2009 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -928,19 +928,19 @@ iop_adma_xor_zero_sum_self_test(struct iop_adma_device *device)
|
|||
|
||||
for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) {
|
||||
xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
|
||||
if (!xor_srcs[src_idx])
|
||||
while (src_idx--) {
|
||||
if (!xor_srcs[src_idx]) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dest = alloc_page(GFP_KERNEL);
|
||||
if (!dest)
|
||||
while (src_idx--) {
|
||||
if (!dest) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill in src buffers */
|
||||
for (src_idx = 0; src_idx < IOP_ADMA_NUM_SRC_TEST; src_idx++) {
|
||||
|
|
@ -1401,7 +1401,7 @@ MODULE_ALIAS("platform:iop-adma");
|
|||
|
||||
static struct platform_driver iop_adma_driver = {
|
||||
.probe = iop_adma_probe,
|
||||
.remove = iop_adma_remove,
|
||||
.remove = __devexit_p(iop_adma_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "iop-adma",
|
||||
|
|
|
|||
|
|
@ -729,7 +729,7 @@ static int ipu_init_channel_buffer(struct idmac_channel *ichan,
|
|||
|
||||
ichan->status = IPU_CHANNEL_READY;
|
||||
|
||||
spin_unlock_irqrestore(ipu->lock, flags);
|
||||
spin_unlock_irqrestore(&ipu->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1019,19 +1019,19 @@ mv_xor_xor_self_test(struct mv_xor_device *device)
|
|||
|
||||
for (src_idx = 0; src_idx < MV_XOR_NUM_SRC_TEST; src_idx++) {
|
||||
xor_srcs[src_idx] = alloc_page(GFP_KERNEL);
|
||||
if (!xor_srcs[src_idx])
|
||||
while (src_idx--) {
|
||||
if (!xor_srcs[src_idx]) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
dest = alloc_page(GFP_KERNEL);
|
||||
if (!dest)
|
||||
while (src_idx--) {
|
||||
if (!dest) {
|
||||
while (src_idx--)
|
||||
__free_page(xor_srcs[src_idx]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Fill in src buffers */
|
||||
for (src_idx = 0; src_idx < MV_XOR_NUM_SRC_TEST; src_idx++) {
|
||||
|
|
@ -1287,7 +1287,7 @@ mv_xor_conf_mbus_windows(struct mv_xor_shared_private *msp,
|
|||
|
||||
static struct platform_driver mv_xor_driver = {
|
||||
.probe = mv_xor_probe,
|
||||
.remove = mv_xor_remove,
|
||||
.remove = __devexit_p(mv_xor_remove),
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = MV_XOR_NAME,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
* linux/drivers/firmware/memmap.c
|
||||
* Copyright (C) 2008 SUSE LINUX Products GmbH
|
||||
* by Bernhard Walle <bwalle@suse.de>
|
||||
* by Bernhard Walle <bernhard.walle@gmx.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License v2.0 as published by
|
||||
|
|
|
|||
|
|
@ -80,18 +80,17 @@ config DRM_I915
|
|||
XFree86 4.4 and above. If unsure, build this and i830 as modules and
|
||||
the X server will load the correct one.
|
||||
|
||||
endchoice
|
||||
|
||||
config DRM_I915_KMS
|
||||
bool "Enable modesetting on intel by default"
|
||||
depends on DRM_I915
|
||||
help
|
||||
Choose this option if you want kernel modesetting enabled by default,
|
||||
and you have a new enough userspace to support this. Running old
|
||||
userspaces with this enabled will cause pain. Note that this causes
|
||||
the driver to bind to PCI devices, which precludes loading things
|
||||
like intelfb.
|
||||
Choose this option if you want kernel modesetting enabled by default,
|
||||
and you have a new enough userspace to support this. Running old
|
||||
userspaces with this enabled will cause pain. Note that this causes
|
||||
the driver to bind to PCI devices, which precludes loading things
|
||||
like intelfb.
|
||||
|
||||
endchoice
|
||||
|
||||
config DRM_MGA
|
||||
tristate "Matrox g200/g400"
|
||||
|
|
|
|||
|
|
@ -420,7 +420,7 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
|
|||
dev->sigdata.lock = NULL;
|
||||
master->lock.hw_lock = NULL; /* SHM removed */
|
||||
master->lock.file_priv = NULL;
|
||||
wake_up_interruptible(&master->lock.lock_queue);
|
||||
wake_up_interruptible_all(&master->lock.lock_queue);
|
||||
}
|
||||
break;
|
||||
case _DRM_AGP:
|
||||
|
|
|
|||
|
|
@ -1741,9 +1741,8 @@ out:
|
|||
* RETURNS:
|
||||
* Zero on success, errno on failure.
|
||||
*/
|
||||
void drm_fb_release(struct file *filp)
|
||||
void drm_fb_release(struct drm_file *priv)
|
||||
{
|
||||
struct drm_file *priv = filp->private_data;
|
||||
struct drm_device *dev = priv->minor->dev;
|
||||
struct drm_framebuffer *fb, *tfb;
|
||||
|
||||
|
|
|
|||
|
|
@ -452,6 +452,59 @@ static void drm_setup_crtcs(struct drm_device *dev)
|
|||
kfree(modes);
|
||||
kfree(enabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_encoder_crtc_ok - can a given crtc drive a given encoder?
|
||||
* @encoder: encoder to test
|
||||
* @crtc: crtc to test
|
||||
*
|
||||
* Return false if @encoder can't be driven by @crtc, true otherwise.
|
||||
*/
|
||||
static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
|
||||
struct drm_crtc *crtc)
|
||||
{
|
||||
struct drm_device *dev;
|
||||
struct drm_crtc *tmp;
|
||||
int crtc_mask = 1;
|
||||
|
||||
WARN(!crtc, "checking null crtc?");
|
||||
|
||||
dev = crtc->dev;
|
||||
|
||||
list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
|
||||
if (tmp == crtc)
|
||||
break;
|
||||
crtc_mask <<= 1;
|
||||
}
|
||||
|
||||
if (encoder->possible_crtcs & crtc_mask)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the CRTC we're going to map each output to vs. its current
|
||||
* CRTC. If they don't match, we have to disable the output and the CRTC
|
||||
* since the driver will have to re-route things.
|
||||
*/
|
||||
static void
|
||||
drm_crtc_prepare_encoders(struct drm_device *dev)
|
||||
{
|
||||
struct drm_encoder_helper_funcs *encoder_funcs;
|
||||
struct drm_encoder *encoder;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
encoder_funcs = encoder->helper_private;
|
||||
/* Disable unused encoders */
|
||||
if (encoder->crtc == NULL)
|
||||
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
|
||||
/* Disable encoders whose CRTC is about to change */
|
||||
if (encoder_funcs->get_crtc &&
|
||||
encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
|
||||
(*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* drm_crtc_set_mode - set a mode
|
||||
* @crtc: CRTC to program
|
||||
|
|
@ -512,8 +565,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
if (drm_mode_equal(&saved_mode, &crtc->mode)) {
|
||||
if (saved_x != crtc->x || saved_y != crtc->y ||
|
||||
depth_changed || bpp_changed) {
|
||||
crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
|
||||
old_fb);
|
||||
ret = !crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
|
||||
old_fb);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
@ -547,12 +600,16 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
|
|||
encoder_funcs->prepare(encoder);
|
||||
}
|
||||
|
||||
drm_crtc_prepare_encoders(dev);
|
||||
|
||||
crtc_funcs->prepare(crtc);
|
||||
|
||||
/* Set up the DPLL and any encoders state that needs to adjust or depend
|
||||
* on the DPLL.
|
||||
*/
|
||||
crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
|
||||
ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
|
||||
if (!ret)
|
||||
goto done;
|
||||
|
||||
list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
|
||||
|
||||
|
|
@ -615,7 +672,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
struct drm_device *dev;
|
||||
struct drm_crtc **save_crtcs, *new_crtc;
|
||||
struct drm_encoder **save_encoders, *new_encoder;
|
||||
struct drm_framebuffer *old_fb;
|
||||
struct drm_framebuffer *old_fb = NULL;
|
||||
bool save_enabled;
|
||||
bool mode_changed = false;
|
||||
bool fb_changed = false;
|
||||
|
|
@ -666,9 +723,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
* and then just flip_or_move it */
|
||||
if (set->crtc->fb != set->fb) {
|
||||
/* If we have no fb then treat it as a full mode set */
|
||||
if (set->crtc->fb == NULL)
|
||||
if (set->crtc->fb == NULL) {
|
||||
DRM_DEBUG("crtc has no fb, full mode set\n");
|
||||
mode_changed = true;
|
||||
else if ((set->fb->bits_per_pixel !=
|
||||
} else if ((set->fb->bits_per_pixel !=
|
||||
set->crtc->fb->bits_per_pixel) ||
|
||||
set->fb->depth != set->crtc->fb->depth)
|
||||
fb_changed = true;
|
||||
|
|
@ -680,7 +738,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
fb_changed = true;
|
||||
|
||||
if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
|
||||
DRM_DEBUG("modes are different\n");
|
||||
DRM_DEBUG("modes are different, full mode set\n");
|
||||
drm_mode_debug_printmodeline(&set->crtc->mode);
|
||||
drm_mode_debug_printmodeline(set->mode);
|
||||
mode_changed = true;
|
||||
|
|
@ -706,6 +764,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
}
|
||||
|
||||
if (new_encoder != connector->encoder) {
|
||||
DRM_DEBUG("encoder changed, full mode switch\n");
|
||||
mode_changed = true;
|
||||
connector->encoder = new_encoder;
|
||||
}
|
||||
|
|
@ -732,10 +791,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
if (set->connectors[ro] == connector)
|
||||
new_crtc = set->crtc;
|
||||
}
|
||||
|
||||
/* Make sure the new CRTC will work with the encoder */
|
||||
if (new_crtc &&
|
||||
!drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
|
||||
ret = -EINVAL;
|
||||
goto fail_set_mode;
|
||||
}
|
||||
if (new_crtc != connector->encoder->crtc) {
|
||||
DRM_DEBUG("crtc changed, full mode switch\n");
|
||||
mode_changed = true;
|
||||
connector->encoder->crtc = new_crtc;
|
||||
}
|
||||
DRM_DEBUG("setting connector %d crtc to %p\n",
|
||||
connector->base.id, new_crtc);
|
||||
}
|
||||
|
||||
/* mode_set_base is not a required function */
|
||||
|
|
@ -752,6 +821,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
|
||||
set->x, set->y,
|
||||
old_fb)) {
|
||||
DRM_ERROR("failed to set mode on crtc %p\n",
|
||||
set->crtc);
|
||||
ret = -EINVAL;
|
||||
goto fail_set_mode;
|
||||
}
|
||||
|
|
@ -765,7 +836,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
old_fb = set->crtc->fb;
|
||||
if (set->crtc->fb != set->fb)
|
||||
set->crtc->fb = set->fb;
|
||||
crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
|
||||
ret = crtc_funcs->mode_set_base(set->crtc,
|
||||
set->x, set->y, old_fb);
|
||||
if (ret != 0)
|
||||
goto fail_set_mode;
|
||||
}
|
||||
|
||||
kfree(save_encoders);
|
||||
|
|
@ -774,9 +848,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
|
|||
|
||||
fail_set_mode:
|
||||
set->crtc->enabled = save_enabled;
|
||||
set->crtc->fb = old_fb;
|
||||
count = 0;
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head)
|
||||
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
|
||||
if (!connector->encoder)
|
||||
continue;
|
||||
|
||||
connector->encoder->crtc = save_crtcs[count++];
|
||||
}
|
||||
fail_no_encoder:
|
||||
kfree(save_crtcs);
|
||||
count = 0;
|
||||
|
|
|
|||
|
|
@ -125,7 +125,7 @@ static bool edid_is_valid(struct edid *edid)
|
|||
DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
|
||||
goto bad;
|
||||
}
|
||||
if (edid->revision <= 0 || edid->revision > 3) {
|
||||
if (edid->revision > 3) {
|
||||
DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
|
||||
goto bad;
|
||||
}
|
||||
|
|
@ -320,10 +320,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
|
|||
mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo);
|
||||
|
||||
mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
|
||||
mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) |
|
||||
mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) |
|
||||
pt->vsync_offset_lo);
|
||||
mode->vsync_end = mode->vsync_start +
|
||||
((pt->vsync_pulse_width_hi << 8) |
|
||||
((pt->vsync_pulse_width_hi << 4) |
|
||||
pt->vsync_pulse_width_lo);
|
||||
mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo);
|
||||
|
||||
|
|
|
|||
|
|
@ -457,6 +457,9 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
if (dev->driver->driver_features & DRIVER_GEM)
|
||||
drm_gem_release(dev, file_priv);
|
||||
|
||||
if (dev->driver->driver_features & DRIVER_MODESET)
|
||||
drm_fb_release(file_priv);
|
||||
|
||||
mutex_lock(&dev->ctxlist_mutex);
|
||||
if (!list_empty(&dev->ctxlist)) {
|
||||
struct drm_ctx_list *pos, *n;
|
||||
|
|
@ -481,6 +484,7 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
mutex_lock(&dev->struct_mutex);
|
||||
|
||||
if (file_priv->is_master) {
|
||||
struct drm_master *master = file_priv->master;
|
||||
struct drm_file *temp;
|
||||
list_for_each_entry(temp, &dev->filelist, lhead) {
|
||||
if ((temp->master == file_priv->master) &&
|
||||
|
|
@ -488,6 +492,19 @@ int drm_release(struct inode *inode, struct file *filp)
|
|||
temp->authenticated = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Since the master is disappearing, so is the
|
||||
* possibility to lock.
|
||||
*/
|
||||
|
||||
if (master->lock.hw_lock) {
|
||||
if (dev->sigdata.lock == master->lock.hw_lock)
|
||||
dev->sigdata.lock = NULL;
|
||||
master->lock.hw_lock = NULL;
|
||||
master->lock.file_priv = NULL;
|
||||
wake_up_interruptible_all(&master->lock.lock_queue);
|
||||
}
|
||||
|
||||
if (file_priv->minor->master == file_priv->master) {
|
||||
/* drop the reference held my the minor */
|
||||
drm_master_put(&file_priv->minor->master);
|
||||
|
|
|
|||
|
|
@ -104,8 +104,8 @@ drm_gem_init(struct drm_device *dev)
|
|||
|
||||
if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
|
||||
DRM_FILE_PAGE_OFFSET_SIZE)) {
|
||||
drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
|
||||
drm_ht_remove(&mm->offset_hash);
|
||||
drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -295,35 +295,37 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
|
|||
return -EBADF;
|
||||
|
||||
again:
|
||||
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
|
||||
return -ENOMEM;
|
||||
if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
spin_lock(&dev->object_name_lock);
|
||||
if (obj->name) {
|
||||
args->name = obj->name;
|
||||
if (!obj->name) {
|
||||
ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
|
||||
&obj->name);
|
||||
args->name = (uint64_t) obj->name;
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
return 0;
|
||||
}
|
||||
ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
|
||||
&obj->name);
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (ret != 0) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
if (ret == -EAGAIN)
|
||||
goto again;
|
||||
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
/* Allocate a reference for the name table. */
|
||||
drm_gem_object_reference(obj);
|
||||
} else {
|
||||
args->name = (uint64_t) obj->name;
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Leave the reference from the lookup around as the
|
||||
* name table now holds one
|
||||
*/
|
||||
args->name = (uint64_t) obj->name;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -448,6 +450,7 @@ drm_gem_object_handle_free(struct kref *kref)
|
|||
spin_lock(&dev->object_name_lock);
|
||||
if (obj->name) {
|
||||
idr_remove(&dev->object_name_idr, obj->name);
|
||||
obj->name = 0;
|
||||
spin_unlock(&dev->object_name_lock);
|
||||
/*
|
||||
* The object name held a reference to this object, drop
|
||||
|
|
@ -460,6 +463,26 @@ drm_gem_object_handle_free(struct kref *kref)
|
|||
}
|
||||
EXPORT_SYMBOL(drm_gem_object_handle_free);
|
||||
|
||||
void drm_gem_vm_open(struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
|
||||
drm_gem_object_reference(obj);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vm_open);
|
||||
|
||||
void drm_gem_vm_close(struct vm_area_struct *vma)
|
||||
{
|
||||
struct drm_gem_object *obj = vma->vm_private_data;
|
||||
struct drm_device *dev = obj->dev;
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(drm_gem_vm_close);
|
||||
|
||||
|
||||
/**
|
||||
* drm_gem_mmap - memory map routine for GEM objects
|
||||
* @filp: DRM file pointer
|
||||
|
|
@ -521,6 +544,14 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
|
|||
#endif
|
||||
vma->vm_page_prot = __pgprot(prot);
|
||||
|
||||
/* Take a ref for this mapping of the object, so that the fault
|
||||
* handler can dereference the mmap offset's pointer to the object.
|
||||
* This reference is cleaned up by the corresponding vm_close
|
||||
* (which should happen whether the vma was created by this call, or
|
||||
* by a vm_open due to mremap or partial unmap or whatever).
|
||||
*/
|
||||
drm_gem_object_reference(obj);
|
||||
|
||||
vma->vm_file = filp; /* Needed for drm_vm_open() */
|
||||
drm_vm_open_locked(vma);
|
||||
|
||||
|
|
|
|||
|
|
@ -435,6 +435,8 @@ EXPORT_SYMBOL(drm_vblank_get);
|
|||
*/
|
||||
void drm_vblank_put(struct drm_device *dev, int crtc)
|
||||
{
|
||||
BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
|
||||
|
||||
/* Last user schedules interrupt disable */
|
||||
if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
|
||||
mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
|
||||
|
|
@ -460,8 +462,9 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
|
|||
* so that interrupts remain enabled in the interim.
|
||||
*/
|
||||
if (!dev->vblank_inmodeset[crtc]) {
|
||||
dev->vblank_inmodeset[crtc] = 1;
|
||||
drm_vblank_get(dev, crtc);
|
||||
dev->vblank_inmodeset[crtc] = 0x1;
|
||||
if (drm_vblank_get(dev, crtc) == 0)
|
||||
dev->vblank_inmodeset[crtc] |= 0x2;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_vblank_pre_modeset);
|
||||
|
|
@ -473,9 +476,12 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
|
|||
if (dev->vblank_inmodeset[crtc]) {
|
||||
spin_lock_irqsave(&dev->vbl_lock, irqflags);
|
||||
dev->vblank_disable_allowed = 1;
|
||||
dev->vblank_inmodeset[crtc] = 0;
|
||||
spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
|
||||
drm_vblank_put(dev, crtc);
|
||||
|
||||
if (dev->vblank_inmodeset[crtc] & 0x2)
|
||||
drm_vblank_put(dev, crtc);
|
||||
|
||||
dev->vblank_inmodeset[crtc] = 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(drm_vblank_post_modeset);
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
|||
__set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (!master->lock.hw_lock) {
|
||||
/* Device has been unregistered */
|
||||
send_sig(SIGTERM, current, 0);
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
|
|
@ -93,7 +94,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
|||
/* Contention */
|
||||
schedule();
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -146,14 +146,6 @@ static void drm_master_destroy(struct kref *kref)
|
|||
|
||||
drm_ht_remove(&master->magiclist);
|
||||
|
||||
if (master->lock.hw_lock) {
|
||||
if (dev->sigdata.lock == master->lock.hw_lock)
|
||||
dev->sigdata.lock = NULL;
|
||||
master->lock.hw_lock = NULL;
|
||||
master->lock.file_priv = NULL;
|
||||
wake_up_interruptible(&master->lock.lock_queue);
|
||||
}
|
||||
|
||||
drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
|
||||
}
|
||||
|
||||
|
|
@ -176,7 +168,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
|
|||
file_priv->minor->master != file_priv->master) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
file_priv->minor->master = drm_master_get(file_priv->master);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
|
|||
dev_priv->ring.map.flags = 0;
|
||||
dev_priv->ring.map.mtrr = 0;
|
||||
|
||||
drm_core_ioremap(&dev_priv->ring.map, dev);
|
||||
drm_core_ioremap_wc(&dev_priv->ring.map, dev);
|
||||
|
||||
if (dev_priv->ring.map.handle == NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
|
|
@ -811,7 +811,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
|
|||
dev_priv->hws_map.flags = 0;
|
||||
dev_priv->hws_map.mtrr = 0;
|
||||
|
||||
drm_core_ioremap(&dev_priv->hws_map, dev);
|
||||
drm_core_ioremap_wc(&dev_priv->hws_map, dev);
|
||||
if (dev_priv->hws_map.handle == NULL) {
|
||||
i915_dma_cleanup(dev);
|
||||
dev_priv->status_gfx_addr = 0;
|
||||
|
|
@ -1090,6 +1090,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
dev_priv->mm.gtt_mapping =
|
||||
io_mapping_create_wc(dev->agp->base,
|
||||
dev->agp->agp_info.aper_size * 1024*1024);
|
||||
if (dev_priv->mm.gtt_mapping == NULL) {
|
||||
ret = -EIO;
|
||||
goto out_rmmap;
|
||||
}
|
||||
|
||||
/* Set up a WC MTRR for non-PAT systems. This is more common than
|
||||
* one would think, because the kernel disables PAT on first
|
||||
* generation Core chips because WC PAT gets overridden by a UC
|
||||
|
|
@ -1100,7 +1105,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
1024 * 1024,
|
||||
MTRR_TYPE_WRCOMB, 1);
|
||||
if (dev_priv->mm.gtt_mtrr < 0) {
|
||||
DRM_INFO("MTRR allocation failed\n. Graphics "
|
||||
DRM_INFO("MTRR allocation failed. Graphics "
|
||||
"performance may suffer.\n");
|
||||
}
|
||||
|
||||
|
|
@ -1122,7 +1127,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
if (!I915_NEED_GFX_HWS(dev)) {
|
||||
ret = i915_init_phys_hws(dev);
|
||||
if (ret != 0)
|
||||
goto out_rmmap;
|
||||
goto out_iomapfree;
|
||||
}
|
||||
|
||||
/* On the 945G/GM, the chipset reports the MSI capability on the
|
||||
|
|
@ -1161,6 +1166,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
|
|||
|
||||
return 0;
|
||||
|
||||
out_iomapfree:
|
||||
io_mapping_free(dev_priv->mm.gtt_mapping);
|
||||
out_rmmap:
|
||||
iounmap(dev_priv->regs);
|
||||
free_priv:
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
#include "i915_drm.h"
|
||||
|
|
@ -66,6 +67,14 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
|
||||
i915_save_state(dev);
|
||||
|
||||
/* If KMS is active, we do the leavevt stuff here */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
if (i915_gem_idle(dev))
|
||||
dev_err(&dev->pdev->dev,
|
||||
"GEM idle failed, resume may fail\n");
|
||||
drm_irq_uninstall(dev);
|
||||
}
|
||||
|
||||
intel_opregion_free(dev);
|
||||
|
||||
if (state.event == PM_EVENT_SUSPEND) {
|
||||
|
|
@ -79,6 +88,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
|
|||
|
||||
static int i915_resume(struct drm_device *dev)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
int ret = 0;
|
||||
|
||||
pci_set_power_state(dev->pdev, PCI_D0);
|
||||
pci_restore_state(dev->pdev);
|
||||
if (pci_enable_device(dev->pdev))
|
||||
|
|
@ -89,11 +101,26 @@ static int i915_resume(struct drm_device *dev)
|
|||
|
||||
intel_opregion_init(dev);
|
||||
|
||||
return 0;
|
||||
/* KMS EnterVT equivalent */
|
||||
if (drm_core_check_feature(dev, DRIVER_MODESET)) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
dev_priv->mm.suspended = 0;
|
||||
|
||||
ret = i915_gem_init_ringbuffer(dev);
|
||||
if (ret != 0)
|
||||
ret = -1;
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_irq_install(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct vm_operations_struct i915_gem_vm_ops = {
|
||||
.fault = i915_gem_fault,
|
||||
.open = drm_gem_vm_open,
|
||||
.close = drm_gem_vm_close,
|
||||
};
|
||||
|
||||
static struct drm_driver driver = {
|
||||
|
|
|
|||
|
|
@ -184,6 +184,8 @@ typedef struct drm_i915_private {
|
|||
unsigned int lvds_dither:1;
|
||||
unsigned int lvds_vbt:1;
|
||||
unsigned int int_crt_support:1;
|
||||
unsigned int lvds_use_ssc:1;
|
||||
int lvds_ssc_freq;
|
||||
|
||||
struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
|
||||
int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
|
||||
|
|
@ -277,7 +279,6 @@ typedef struct drm_i915_private {
|
|||
u8 saveAR_INDEX;
|
||||
u8 saveAR[21];
|
||||
u8 saveDACMASK;
|
||||
u8 saveDACDATA[256*3]; /* 256 3-byte colors */
|
||||
u8 saveCR[37];
|
||||
|
||||
struct {
|
||||
|
|
@ -455,6 +456,12 @@ struct drm_i915_gem_object {
|
|||
|
||||
/** for phy allocated objects */
|
||||
struct drm_i915_gem_phys_object *phys_obj;
|
||||
|
||||
/**
|
||||
* Used for checking the object doesn't appear more than once
|
||||
* in an execbuffer object list.
|
||||
*/
|
||||
int in_execbuffer;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -616,6 +623,7 @@ int i915_gem_init_ringbuffer(struct drm_device *dev);
|
|||
void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
|
||||
int i915_gem_do_init(struct drm_device *dev, unsigned long start,
|
||||
unsigned long end);
|
||||
int i915_gem_idle(struct drm_device *dev);
|
||||
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
|
||||
int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
|
||||
int write);
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@
|
|||
|
||||
#define I915_GEM_GPU_DOMAINS (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
|
||||
|
||||
static void
|
||||
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
||||
uint32_t read_domains,
|
||||
uint32_t write_domain);
|
||||
static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
|
||||
static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
|
||||
static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
|
||||
|
|
@ -607,8 +603,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
case -EAGAIN:
|
||||
return VM_FAULT_OOM;
|
||||
case -EFAULT:
|
||||
case -EBUSY:
|
||||
DRM_ERROR("can't insert pfn?? fault or busy...\n");
|
||||
return VM_FAULT_SIGBUS;
|
||||
default:
|
||||
return VM_FAULT_NOPAGE;
|
||||
|
|
@ -684,6 +678,30 @@ out_free_list:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
i915_gem_free_mmap_offset(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
struct drm_gem_mm *mm = dev->mm_private;
|
||||
struct drm_map_list *list;
|
||||
|
||||
list = &obj->map_list;
|
||||
drm_ht_remove_item(&mm->offset_hash, &list->hash);
|
||||
|
||||
if (list->file_offset_node) {
|
||||
drm_mm_put_block(list->file_offset_node);
|
||||
list->file_offset_node = NULL;
|
||||
}
|
||||
|
||||
if (list->map) {
|
||||
drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER);
|
||||
list->map = NULL;
|
||||
}
|
||||
|
||||
obj_priv->mmap_offset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* i915_gem_get_gtt_alignment - return required GTT alignment for an object
|
||||
* @obj: object to check
|
||||
|
|
@ -758,8 +776,11 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
|
|||
|
||||
if (!obj_priv->mmap_offset) {
|
||||
ret = i915_gem_create_mmap_offset(obj);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
args->offset = obj_priv->mmap_offset;
|
||||
|
|
@ -1030,6 +1051,9 @@ i915_gem_retire_requests(struct drm_device *dev)
|
|||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
uint32_t seqno;
|
||||
|
||||
if (!dev_priv->hw_status_page)
|
||||
return;
|
||||
|
||||
seqno = i915_get_gem_seqno(dev);
|
||||
|
||||
while (!list_empty(&dev_priv->mm.request_list)) {
|
||||
|
|
@ -1452,7 +1476,7 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
|
|||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
int regnum = obj_priv->fence_reg;
|
||||
int tile_width;
|
||||
uint32_t val;
|
||||
uint32_t fence_reg, val;
|
||||
uint32_t pitch_val;
|
||||
|
||||
if ((obj_priv->gtt_offset & ~I915_FENCE_START_MASK) ||
|
||||
|
|
@ -1479,7 +1503,11 @@ static void i915_write_fence_reg(struct drm_i915_fence_reg *reg)
|
|||
val |= pitch_val << I830_FENCE_PITCH_SHIFT;
|
||||
val |= I830_FENCE_REG_VALID;
|
||||
|
||||
I915_WRITE(FENCE_REG_830_0 + (regnum * 4), val);
|
||||
if (regnum < 8)
|
||||
fence_reg = FENCE_REG_830_0 + (regnum * 4);
|
||||
else
|
||||
fence_reg = FENCE_REG_945_8 + ((regnum - 8) * 4);
|
||||
I915_WRITE(fence_reg, val);
|
||||
}
|
||||
|
||||
static void i830_write_fence_reg(struct drm_i915_fence_reg *reg)
|
||||
|
|
@ -1533,7 +1561,8 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write)
|
|||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
struct drm_i915_fence_reg *reg = NULL;
|
||||
int i, ret;
|
||||
struct drm_i915_gem_object *old_obj_priv = NULL;
|
||||
int i, ret, avail;
|
||||
|
||||
switch (obj_priv->tiling_mode) {
|
||||
case I915_TILING_NONE:
|
||||
|
|
@ -1556,25 +1585,46 @@ i915_gem_object_get_fence_reg(struct drm_gem_object *obj, bool write)
|
|||
}
|
||||
|
||||
/* First try to find a free reg */
|
||||
try_again:
|
||||
avail = 0;
|
||||
for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) {
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
if (!reg->obj)
|
||||
break;
|
||||
|
||||
old_obj_priv = reg->obj->driver_private;
|
||||
if (!old_obj_priv->pin_count)
|
||||
avail++;
|
||||
}
|
||||
|
||||
/* None available, try to steal one or wait for a user to finish */
|
||||
if (i == dev_priv->num_fence_regs) {
|
||||
struct drm_i915_gem_object *old_obj_priv = NULL;
|
||||
uint32_t seqno = dev_priv->mm.next_gem_seqno;
|
||||
loff_t offset;
|
||||
|
||||
try_again:
|
||||
/* Could try to use LRU here instead... */
|
||||
if (avail == 0)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = dev_priv->fence_reg_start;
|
||||
i < dev_priv->num_fence_regs; i++) {
|
||||
uint32_t this_seqno;
|
||||
|
||||
reg = &dev_priv->fence_regs[i];
|
||||
old_obj_priv = reg->obj->driver_private;
|
||||
if (!old_obj_priv->pin_count)
|
||||
|
||||
if (old_obj_priv->pin_count)
|
||||
continue;
|
||||
|
||||
/* i915 uses fences for GPU access to tiled buffers */
|
||||
if (IS_I965G(dev) || !old_obj_priv->active)
|
||||
break;
|
||||
|
||||
/* find the seqno of the first available fence */
|
||||
this_seqno = old_obj_priv->last_rendering_seqno;
|
||||
if (this_seqno != 0 &&
|
||||
reg->obj->write_domain == 0 &&
|
||||
i915_seqno_passed(seqno, this_seqno))
|
||||
seqno = this_seqno;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1582,15 +1632,25 @@ try_again:
|
|||
* objects to finish before trying again.
|
||||
*/
|
||||
if (i == dev_priv->num_fence_regs) {
|
||||
ret = i915_gem_object_set_to_gtt_domain(reg->obj, 0);
|
||||
if (ret) {
|
||||
WARN(ret != -ERESTARTSYS,
|
||||
"switch to GTT domain failed: %d\n", ret);
|
||||
return ret;
|
||||
if (seqno == dev_priv->mm.next_gem_seqno) {
|
||||
i915_gem_flush(dev,
|
||||
I915_GEM_GPU_DOMAINS,
|
||||
I915_GEM_GPU_DOMAINS);
|
||||
seqno = i915_add_request(dev,
|
||||
I915_GEM_GPU_DOMAINS);
|
||||
if (seqno == 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = i915_wait_request(dev, seqno);
|
||||
if (ret)
|
||||
return ret;
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
BUG_ON(old_obj_priv->active ||
|
||||
(reg->obj->write_domain & I915_GEM_GPU_DOMAINS));
|
||||
|
||||
/*
|
||||
* Zap this virtual mapping so we can set up a fence again
|
||||
* for this object next time we need it.
|
||||
|
|
@ -1631,8 +1691,17 @@ i915_gem_clear_fence_reg(struct drm_gem_object *obj)
|
|||
|
||||
if (IS_I965G(dev))
|
||||
I915_WRITE64(FENCE_REG_965_0 + (obj_priv->fence_reg * 8), 0);
|
||||
else
|
||||
I915_WRITE(FENCE_REG_830_0 + (obj_priv->fence_reg * 4), 0);
|
||||
else {
|
||||
uint32_t fence_reg;
|
||||
|
||||
if (obj_priv->fence_reg < 8)
|
||||
fence_reg = FENCE_REG_830_0 + obj_priv->fence_reg * 4;
|
||||
else
|
||||
fence_reg = FENCE_REG_945_8 + (obj_priv->fence_reg -
|
||||
8) * 4;
|
||||
|
||||
I915_WRITE(fence_reg, 0);
|
||||
}
|
||||
|
||||
dev_priv->fence_regs[obj_priv->fence_reg].obj = NULL;
|
||||
obj_priv->fence_reg = I915_FENCE_REG_NONE;
|
||||
|
|
@ -1996,30 +2065,28 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
|
|||
* drm_agp_chipset_flush
|
||||
*/
|
||||
static void
|
||||
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
||||
uint32_t read_domains,
|
||||
uint32_t write_domain)
|
||||
i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
uint32_t invalidate_domains = 0;
|
||||
uint32_t flush_domains = 0;
|
||||
|
||||
BUG_ON(read_domains & I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(write_domain == I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
|
||||
BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
|
||||
|
||||
#if WATCH_BUF
|
||||
DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
|
||||
__func__, obj,
|
||||
obj->read_domains, read_domains,
|
||||
obj->write_domain, write_domain);
|
||||
obj->read_domains, obj->pending_read_domains,
|
||||
obj->write_domain, obj->pending_write_domain);
|
||||
#endif
|
||||
/*
|
||||
* If the object isn't moving to a new write domain,
|
||||
* let the object stay in multiple read domains
|
||||
*/
|
||||
if (write_domain == 0)
|
||||
read_domains |= obj->read_domains;
|
||||
if (obj->pending_write_domain == 0)
|
||||
obj->pending_read_domains |= obj->read_domains;
|
||||
else
|
||||
obj_priv->dirty = 1;
|
||||
|
||||
|
|
@ -2029,15 +2096,17 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
|||
* any read domains which differ from the old
|
||||
* write domain
|
||||
*/
|
||||
if (obj->write_domain && obj->write_domain != read_domains) {
|
||||
if (obj->write_domain &&
|
||||
obj->write_domain != obj->pending_read_domains) {
|
||||
flush_domains |= obj->write_domain;
|
||||
invalidate_domains |= read_domains & ~obj->write_domain;
|
||||
invalidate_domains |=
|
||||
obj->pending_read_domains & ~obj->write_domain;
|
||||
}
|
||||
/*
|
||||
* Invalidate any read caches which may have
|
||||
* stale data. That is, any new read domains.
|
||||
*/
|
||||
invalidate_domains |= read_domains & ~obj->read_domains;
|
||||
invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
|
||||
if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
|
||||
#if WATCH_BUF
|
||||
DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
|
||||
|
|
@ -2046,9 +2115,15 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
|
|||
i915_gem_clflush_object(obj);
|
||||
}
|
||||
|
||||
if ((write_domain | flush_domains) != 0)
|
||||
obj->write_domain = write_domain;
|
||||
obj->read_domains = read_domains;
|
||||
/* The actual obj->write_domain will be updated with
|
||||
* pending_write_domain after we emit the accumulated flush for all
|
||||
* of our domain changes in execbuffers (which clears objects'
|
||||
* write_domains). So if we have a current write domain that we
|
||||
* aren't changing, set pending_write_domain to that.
|
||||
*/
|
||||
if (flush_domains == 0 && obj->pending_write_domain == 0)
|
||||
obj->pending_write_domain = obj->write_domain;
|
||||
obj->read_domains = obj->pending_read_domains;
|
||||
|
||||
dev->invalidate_domains |= invalidate_domains;
|
||||
dev->flush_domains |= flush_domains;
|
||||
|
|
@ -2251,6 +2326,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
|
|||
(int) reloc.offset,
|
||||
reloc.read_domains,
|
||||
reloc.write_domain);
|
||||
drm_gem_object_unreference(target_obj);
|
||||
i915_gem_object_unpin(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -2437,6 +2514,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
struct drm_i915_gem_exec_object *exec_list = NULL;
|
||||
struct drm_gem_object **object_list = NULL;
|
||||
struct drm_gem_object *batch_obj;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
int ret, i, pinned = 0;
|
||||
uint64_t exec_offset;
|
||||
uint32_t seqno, flush_domains;
|
||||
|
|
@ -2480,13 +2558,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
if (dev_priv->mm.wedged) {
|
||||
DRM_ERROR("Execbuf while wedged\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EIO;
|
||||
ret = -EIO;
|
||||
goto pre_mutex_err;
|
||||
}
|
||||
|
||||
if (dev_priv->mm.suspended) {
|
||||
DRM_ERROR("Execbuf while VT-switched.\n");
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EBUSY;
|
||||
ret = -EBUSY;
|
||||
goto pre_mutex_err;
|
||||
}
|
||||
|
||||
/* Look up object handles */
|
||||
|
|
@ -2499,6 +2579,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
ret = -EBADF;
|
||||
goto err;
|
||||
}
|
||||
|
||||
obj_priv = object_list[i]->driver_private;
|
||||
if (obj_priv->in_execbuffer) {
|
||||
DRM_ERROR("Object %p appears more than once in object list\n",
|
||||
object_list[i]);
|
||||
ret = -EBADF;
|
||||
goto err;
|
||||
}
|
||||
obj_priv->in_execbuffer = true;
|
||||
}
|
||||
|
||||
/* Pin and relocate */
|
||||
|
|
@ -2554,9 +2643,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
struct drm_gem_object *obj = object_list[i];
|
||||
|
||||
/* Compute new gpu domains and update invalidate/flush */
|
||||
i915_gem_object_set_to_gpu_domain(obj,
|
||||
obj->pending_read_domains,
|
||||
obj->pending_write_domain);
|
||||
i915_gem_object_set_to_gpu_domain(obj);
|
||||
}
|
||||
|
||||
i915_verify_inactive(dev, __FILE__, __LINE__);
|
||||
|
|
@ -2575,6 +2662,12 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
(void)i915_add_request(dev, dev->flush_domains);
|
||||
}
|
||||
|
||||
for (i = 0; i < args->buffer_count; i++) {
|
||||
struct drm_gem_object *obj = object_list[i];
|
||||
|
||||
obj->write_domain = obj->pending_write_domain;
|
||||
}
|
||||
|
||||
i915_verify_inactive(dev, __FILE__, __LINE__);
|
||||
|
||||
#if WATCH_COHERENCY
|
||||
|
|
@ -2632,24 +2725,32 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
|
|||
|
||||
i915_verify_inactive(dev, __FILE__, __LINE__);
|
||||
|
||||
/* Copy the new buffer offsets back to the user's exec list. */
|
||||
ret = copy_to_user((struct drm_i915_relocation_entry __user *)
|
||||
(uintptr_t) args->buffers_ptr,
|
||||
exec_list,
|
||||
sizeof(*exec_list) * args->buffer_count);
|
||||
if (ret)
|
||||
DRM_ERROR("failed to copy %d exec entries "
|
||||
"back to user (%d)\n",
|
||||
args->buffer_count, ret);
|
||||
err:
|
||||
for (i = 0; i < pinned; i++)
|
||||
i915_gem_object_unpin(object_list[i]);
|
||||
|
||||
for (i = 0; i < args->buffer_count; i++)
|
||||
for (i = 0; i < args->buffer_count; i++) {
|
||||
if (object_list[i]) {
|
||||
obj_priv = object_list[i]->driver_private;
|
||||
obj_priv->in_execbuffer = false;
|
||||
}
|
||||
drm_gem_object_unreference(object_list[i]);
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (!ret) {
|
||||
/* Copy the new buffer offsets back to the user's exec list. */
|
||||
ret = copy_to_user((struct drm_i915_relocation_entry __user *)
|
||||
(uintptr_t) args->buffers_ptr,
|
||||
exec_list,
|
||||
sizeof(*exec_list) * args->buffer_count);
|
||||
if (ret)
|
||||
DRM_ERROR("failed to copy %d exec entries "
|
||||
"back to user (%d)\n",
|
||||
args->buffer_count, ret);
|
||||
}
|
||||
|
||||
pre_mutex_err:
|
||||
drm_free(object_list, sizeof(*object_list) * args->buffer_count,
|
||||
DRM_MEM_DRIVER);
|
||||
|
|
@ -2671,17 +2772,24 @@ i915_gem_object_pin(struct drm_gem_object *obj, uint32_t alignment)
|
|||
ret = i915_gem_object_bind_to_gtt(obj, alignment);
|
||||
if (ret != 0) {
|
||||
if (ret != -EBUSY && ret != -ERESTARTSYS)
|
||||
DRM_ERROR("Failure to bind: %d", ret);
|
||||
DRM_ERROR("Failure to bind: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Pre-965 chips need a fence register set up in order to
|
||||
* properly handle tiled surfaces.
|
||||
*/
|
||||
if (!IS_I965G(dev) &&
|
||||
obj_priv->fence_reg == I915_FENCE_REG_NONE &&
|
||||
obj_priv->tiling_mode != I915_TILING_NONE) {
|
||||
ret = i915_gem_object_get_fence_reg(obj, true);
|
||||
if (ret != 0) {
|
||||
if (ret != -EBUSY && ret != -ERESTARTSYS)
|
||||
DRM_ERROR("Failure to install fence: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
* Pre-965 chips need a fence register set up in order to
|
||||
* properly handle tiled surfaces.
|
||||
*/
|
||||
if (!IS_I965G(dev) &&
|
||||
obj_priv->fence_reg == I915_FENCE_REG_NONE &&
|
||||
obj_priv->tiling_mode != I915_TILING_NONE)
|
||||
i915_gem_object_get_fence_reg(obj, true);
|
||||
}
|
||||
obj_priv->pin_count++;
|
||||
|
||||
|
|
@ -2753,6 +2861,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
|
|||
if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
|
||||
DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
|
||||
args->handle);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -2833,6 +2942,13 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
|
|||
return -EBADF;
|
||||
}
|
||||
|
||||
/* Update the active list for the hardware's current position.
|
||||
* Otherwise this only updates on a delayed timer or when irqs are
|
||||
* actually unmasked, and our working set ends up being larger than
|
||||
* required.
|
||||
*/
|
||||
i915_gem_retire_requests(dev);
|
||||
|
||||
obj_priv = obj->driver_private;
|
||||
/* Don't count being on the flushing list against the object being
|
||||
* done. Otherwise, a buffer left on the flushing list but not getting
|
||||
|
|
@ -2885,9 +3001,6 @@ int i915_gem_init_object(struct drm_gem_object *obj)
|
|||
void i915_gem_free_object(struct drm_gem_object *obj)
|
||||
{
|
||||
struct drm_device *dev = obj->dev;
|
||||
struct drm_gem_mm *mm = dev->mm_private;
|
||||
struct drm_map_list *list;
|
||||
struct drm_map *map;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
while (obj_priv->pin_count > 0)
|
||||
|
|
@ -2898,19 +3011,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)
|
|||
|
||||
i915_gem_object_unbind(obj);
|
||||
|
||||
list = &obj->map_list;
|
||||
drm_ht_remove_item(&mm->offset_hash, &list->hash);
|
||||
|
||||
if (list->file_offset_node) {
|
||||
drm_mm_put_block(list->file_offset_node);
|
||||
list->file_offset_node = NULL;
|
||||
}
|
||||
|
||||
map = list->map;
|
||||
if (map) {
|
||||
drm_free(map, sizeof(*map), DRM_MEM_DRIVER);
|
||||
list->map = NULL;
|
||||
}
|
||||
i915_gem_free_mmap_offset(obj);
|
||||
|
||||
drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
|
||||
drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
|
||||
|
|
@ -2949,7 +3050,7 @@ i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
int
|
||||
i915_gem_idle(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
|
|
@ -3095,6 +3196,7 @@ i915_gem_init_hws(struct drm_device *dev)
|
|||
if (dev_priv->hw_status_page == NULL) {
|
||||
DRM_ERROR("Failed to map status page.\n");
|
||||
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -3107,6 +3209,31 @@ i915_gem_init_hws(struct drm_device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
i915_gem_cleanup_hws(struct drm_device *dev)
|
||||
{
|
||||
drm_i915_private_t *dev_priv = dev->dev_private;
|
||||
struct drm_gem_object *obj;
|
||||
struct drm_i915_gem_object *obj_priv;
|
||||
|
||||
if (dev_priv->hws_obj == NULL)
|
||||
return;
|
||||
|
||||
obj = dev_priv->hws_obj;
|
||||
obj_priv = obj->driver_private;
|
||||
|
||||
kunmap(obj_priv->page_list[0]);
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
dev_priv->hws_obj = NULL;
|
||||
|
||||
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
|
||||
dev_priv->hw_status_page = NULL;
|
||||
|
||||
/* Write high address into HWS_PGA when disabling. */
|
||||
I915_WRITE(HWS_PGA, 0x1ffff000);
|
||||
}
|
||||
|
||||
int
|
||||
i915_gem_init_ringbuffer(struct drm_device *dev)
|
||||
{
|
||||
|
|
@ -3124,6 +3251,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
|||
obj = drm_gem_object_alloc(dev, 128 * 1024);
|
||||
if (obj == NULL) {
|
||||
DRM_ERROR("Failed to allocate ringbuffer\n");
|
||||
i915_gem_cleanup_hws(dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
obj_priv = obj->driver_private;
|
||||
|
|
@ -3131,6 +3259,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
|||
ret = i915_gem_object_pin(obj, 4096);
|
||||
if (ret != 0) {
|
||||
drm_gem_object_unreference(obj);
|
||||
i915_gem_cleanup_hws(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -3148,7 +3277,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
|
|||
if (ring->map.handle == NULL) {
|
||||
DRM_ERROR("Failed to map ringbuffer.\n");
|
||||
memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
i915_gem_cleanup_hws(dev);
|
||||
return -EINVAL;
|
||||
}
|
||||
ring->ring_obj = obj;
|
||||
|
|
@ -3228,20 +3359,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
|
|||
dev_priv->ring.ring_obj = NULL;
|
||||
memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
|
||||
|
||||
if (dev_priv->hws_obj != NULL) {
|
||||
struct drm_gem_object *obj = dev_priv->hws_obj;
|
||||
struct drm_i915_gem_object *obj_priv = obj->driver_private;
|
||||
|
||||
kunmap(obj_priv->page_list[0]);
|
||||
i915_gem_object_unpin(obj);
|
||||
drm_gem_object_unreference(obj);
|
||||
dev_priv->hws_obj = NULL;
|
||||
memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
|
||||
dev_priv->hw_status_page = NULL;
|
||||
|
||||
/* Write high address into HWS_PGA when disabling. */
|
||||
I915_WRITE(HWS_PGA, 0x1ffff000);
|
||||
}
|
||||
i915_gem_cleanup_hws(dev);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -3497,7 +3615,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
|
|||
user_data = (char __user *) (uintptr_t) args->data_ptr;
|
||||
obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
|
||||
|
||||
DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
|
||||
DRM_DEBUG("obj_addr %p, %lld\n", obj_addr, args->size);
|
||||
ret = copy_from_user(obj_addr, user_data, args->size);
|
||||
if (ret)
|
||||
return -EFAULT;
|
||||
|
|
|
|||
|
|
@ -299,9 +299,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
|
|||
}
|
||||
obj_priv->stride = args->stride;
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -340,9 +339,8 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
|
|||
DRM_ERROR("unknown tiling mode\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -383,12 +383,13 @@ int i915_irq_emit(struct drm_device *dev, void *data,
|
|||
drm_i915_irq_emit_t *emit = data;
|
||||
int result;
|
||||
|
||||
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
if (!dev_priv) {
|
||||
DRM_ERROR("called with no initialization\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
|
||||
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
result = i915_emit_irq(dev);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
|
|
|||
|
|
@ -184,6 +184,7 @@
|
|||
* Fence registers
|
||||
*/
|
||||
#define FENCE_REG_830_0 0x2000
|
||||
#define FENCE_REG_945_8 0x3000
|
||||
#define I830_FENCE_START_MASK 0x07f80000
|
||||
#define I830_FENCE_TILING_Y_SHIFT 12
|
||||
#define I830_FENCE_SIZE_BITS(size) ((ffs((size) >> 19) - 1) << 8)
|
||||
|
|
|
|||
|
|
@ -119,11 +119,6 @@ static void i915_save_vga(struct drm_device *dev)
|
|||
|
||||
/* VGA color palette registers */
|
||||
dev_priv->saveDACMASK = I915_READ8(VGA_DACMASK);
|
||||
/* DACCRX automatically increments during read */
|
||||
I915_WRITE8(VGA_DACRX, 0);
|
||||
/* Read 3 bytes of color data from each index */
|
||||
for (i = 0; i < 256 * 3; i++)
|
||||
dev_priv->saveDACDATA[i] = I915_READ8(VGA_DACDATA);
|
||||
|
||||
/* MSR bits */
|
||||
dev_priv->saveMSR = I915_READ8(VGA_MSR_READ);
|
||||
|
|
@ -225,12 +220,6 @@ static void i915_restore_vga(struct drm_device *dev)
|
|||
|
||||
/* VGA color palette registers */
|
||||
I915_WRITE8(VGA_DACMASK, dev_priv->saveDACMASK);
|
||||
/* DACCRX automatically increments during read */
|
||||
I915_WRITE8(VGA_DACWX, 0);
|
||||
/* Read 3 bytes of color data from each index */
|
||||
for (i = 0; i < 256 * 3; i++)
|
||||
I915_WRITE8(VGA_DACDATA, dev_priv->saveDACDATA[i]);
|
||||
|
||||
}
|
||||
|
||||
int i915_save_state(struct drm_device *dev)
|
||||
|
|
|
|||
|
|
@ -111,6 +111,12 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
|
|||
panel_fixed_mode->clock = dvo_timing->clock * 10;
|
||||
panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
|
||||
|
||||
/* Some VBTs have bogus h/vtotal values */
|
||||
if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
|
||||
panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
|
||||
if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
|
||||
panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
|
||||
|
||||
drm_mode_set_name(panel_fixed_mode);
|
||||
|
||||
dev_priv->vbt_mode = panel_fixed_mode;
|
||||
|
|
@ -135,6 +141,14 @@ parse_general_features(struct drm_i915_private *dev_priv,
|
|||
if (general) {
|
||||
dev_priv->int_tv_support = general->int_tv_support;
|
||||
dev_priv->int_crt_support = general->int_crt_support;
|
||||
dev_priv->lvds_use_ssc = general->enable_ssc;
|
||||
|
||||
if (dev_priv->lvds_use_ssc) {
|
||||
if (IS_I855(dev_priv->dev))
|
||||
dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
|
||||
else
|
||||
dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,12 +90,12 @@ typedef struct {
|
|||
#define I9XX_DOT_MAX 400000
|
||||
#define I9XX_VCO_MIN 1400000
|
||||
#define I9XX_VCO_MAX 2800000
|
||||
#define I9XX_N_MIN 3
|
||||
#define I9XX_N_MAX 8
|
||||
#define I9XX_N_MIN 1
|
||||
#define I9XX_N_MAX 6
|
||||
#define I9XX_M_MIN 70
|
||||
#define I9XX_M_MAX 120
|
||||
#define I9XX_M1_MIN 10
|
||||
#define I9XX_M1_MAX 20
|
||||
#define I9XX_M1_MAX 22
|
||||
#define I9XX_M2_MIN 5
|
||||
#define I9XX_M2_MAX 9
|
||||
#define I9XX_P_SDVO_DAC_MIN 5
|
||||
|
|
@ -189,9 +189,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
|
|||
return limit;
|
||||
}
|
||||
|
||||
/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
|
||||
|
||||
static void i8xx_clock(int refclk, intel_clock_t *clock)
|
||||
static void intel_clock(int refclk, intel_clock_t *clock)
|
||||
{
|
||||
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
|
||||
clock->p = clock->p1 * clock->p2;
|
||||
|
|
@ -199,25 +197,6 @@ static void i8xx_clock(int refclk, intel_clock_t *clock)
|
|||
clock->dot = clock->vco / clock->p;
|
||||
}
|
||||
|
||||
/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
|
||||
|
||||
static void i9xx_clock(int refclk, intel_clock_t *clock)
|
||||
{
|
||||
clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
|
||||
clock->p = clock->p1 * clock->p2;
|
||||
clock->vco = refclk * clock->m / (clock->n + 2);
|
||||
clock->dot = clock->vco / clock->p;
|
||||
}
|
||||
|
||||
static void intel_clock(struct drm_device *dev, int refclk,
|
||||
intel_clock_t *clock)
|
||||
{
|
||||
if (IS_I9XX(dev))
|
||||
i9xx_clock (refclk, clock);
|
||||
else
|
||||
i8xx_clock (refclk, clock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether any output on the specified pipe is of the specified type
|
||||
*/
|
||||
|
|
@ -238,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
|
|||
return false;
|
||||
}
|
||||
|
||||
#define INTELPllInvalid(s) { /* ErrorF (s) */; return false; }
|
||||
#define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0)
|
||||
/**
|
||||
* Returns whether the given set of divisors are valid for a given refclk with
|
||||
* the given connectors.
|
||||
|
|
@ -318,7 +297,7 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
|
|||
clock.p1 <= limit->p1.max; clock.p1++) {
|
||||
int this_err;
|
||||
|
||||
intel_clock(dev, refclk, &clock);
|
||||
intel_clock(refclk, &clock);
|
||||
|
||||
if (!intel_PLL_is_valid(crtc, &clock))
|
||||
continue;
|
||||
|
|
@ -343,7 +322,7 @@ intel_wait_for_vblank(struct drm_device *dev)
|
|||
udelay(20000);
|
||||
}
|
||||
|
||||
static void
|
||||
static int
|
||||
intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
|
|
@ -361,11 +340,21 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
|
||||
int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
|
||||
u32 dspcntr, alignment;
|
||||
int ret;
|
||||
|
||||
/* no fb bound */
|
||||
if (!crtc->fb) {
|
||||
DRM_DEBUG("No FB bound\n");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
case 1:
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
intel_fb = to_intel_framebuffer(crtc->fb);
|
||||
|
|
@ -377,28 +366,30 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
alignment = 64 * 1024;
|
||||
break;
|
||||
case I915_TILING_X:
|
||||
if (IS_I9XX(dev))
|
||||
alignment = 1024 * 1024;
|
||||
else
|
||||
alignment = 512 * 1024;
|
||||
/* pin() will align the object as required by fence */
|
||||
alignment = 0;
|
||||
break;
|
||||
case I915_TILING_Y:
|
||||
/* FIXME: Is this true? */
|
||||
DRM_ERROR("Y tiled not allowed for scan out buffers\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
if (i915_gem_object_pin(intel_fb->obj, alignment))
|
||||
return;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
ret = i915_gem_object_pin(intel_fb->obj, alignment);
|
||||
if (ret != 0) {
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
|
||||
|
||||
Start = obj_priv->gtt_offset;
|
||||
Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
|
||||
|
||||
I915_WRITE(dspstride, crtc->fb->pitch);
|
||||
ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
|
||||
if (ret != 0) {
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dspcntr = I915_READ(dspcntr_reg);
|
||||
/* Mask out pixel format bits in case we change it */
|
||||
|
|
@ -419,11 +410,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
break;
|
||||
default:
|
||||
DRM_ERROR("Unknown color depth\n");
|
||||
return;
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return -EINVAL;
|
||||
}
|
||||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
Start = obj_priv->gtt_offset;
|
||||
Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
|
||||
|
||||
DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
|
||||
I915_WRITE(dspstride, crtc->fb->pitch);
|
||||
if (IS_I965G(dev)) {
|
||||
I915_WRITE(dspbase, Offset);
|
||||
I915_READ(dspbase);
|
||||
|
|
@ -440,27 +437,24 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
|
|||
intel_fb = to_intel_framebuffer(old_fb);
|
||||
i915_gem_object_unpin(intel_fb->obj);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
if (!dev->primary->master)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
master_priv = dev->primary->master->driver_priv;
|
||||
if (!master_priv->sarea_priv)
|
||||
return;
|
||||
return 0;
|
||||
|
||||
switch (pipe) {
|
||||
case 0:
|
||||
master_priv->sarea_priv->pipeA_x = x;
|
||||
master_priv->sarea_priv->pipeA_y = y;
|
||||
break;
|
||||
case 1:
|
||||
if (pipe) {
|
||||
master_priv->sarea_priv->pipeB_x = x;
|
||||
master_priv->sarea_priv->pipeB_y = y;
|
||||
break;
|
||||
default:
|
||||
DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
|
||||
break;
|
||||
} else {
|
||||
master_priv->sarea_priv->pipeA_x = x;
|
||||
master_priv->sarea_priv->pipeA_y = y;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -708,11 +702,11 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
static int intel_crtc_mode_set(struct drm_crtc *crtc,
|
||||
struct drm_display_mode *mode,
|
||||
struct drm_display_mode *adjusted_mode,
|
||||
int x, int y,
|
||||
struct drm_framebuffer *old_fb)
|
||||
{
|
||||
struct drm_device *dev = crtc->dev;
|
||||
struct drm_i915_private *dev_priv = dev->dev_private;
|
||||
|
|
@ -732,13 +726,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
|
||||
int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
|
||||
int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
|
||||
int refclk;
|
||||
int refclk, num_outputs = 0;
|
||||
intel_clock_t clock;
|
||||
u32 dpll = 0, fp = 0, dspcntr, pipeconf;
|
||||
bool ok, is_sdvo = false, is_dvo = false;
|
||||
bool is_crt = false, is_lvds = false, is_tv = false;
|
||||
struct drm_mode_config *mode_config = &dev->mode_config;
|
||||
struct drm_connector *connector;
|
||||
int ret;
|
||||
|
||||
drm_vblank_pre_modeset(dev, pipe);
|
||||
|
||||
|
|
@ -768,9 +763,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
is_crt = true;
|
||||
break;
|
||||
}
|
||||
|
||||
num_outputs++;
|
||||
}
|
||||
|
||||
if (IS_I9XX(dev)) {
|
||||
if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) {
|
||||
refclk = dev_priv->lvds_ssc_freq * 1000;
|
||||
DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000);
|
||||
} else if (IS_I9XX(dev)) {
|
||||
refclk = 96000;
|
||||
} else {
|
||||
refclk = 48000;
|
||||
|
|
@ -779,7 +779,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
|
||||
if (!ok) {
|
||||
DRM_ERROR("Couldn't find PLL settings for mode!\n");
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
|
||||
|
|
@ -829,11 +829,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
}
|
||||
}
|
||||
|
||||
if (is_tv) {
|
||||
if (is_sdvo && is_tv)
|
||||
dpll |= PLL_REF_INPUT_TVCLKINBC;
|
||||
else if (is_tv)
|
||||
/* XXX: just matching BIOS for now */
|
||||
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
|
||||
/* dpll |= PLL_REF_INPUT_TVCLKINBC; */
|
||||
dpll |= 3;
|
||||
}
|
||||
else if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2)
|
||||
dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
|
||||
else
|
||||
dpll |= PLL_REF_INPUT_DREFCLK;
|
||||
|
||||
|
|
@ -950,9 +953,13 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
|
|||
I915_WRITE(dspcntr_reg, dspcntr);
|
||||
|
||||
/* Flush the plane changes */
|
||||
intel_pipe_set_base(crtc, x, y, old_fb);
|
||||
ret = intel_pipe_set_base(crtc, x, y, old_fb);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
drm_vblank_post_modeset(dev, pipe);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Loads the palette/gamma unit for the CRTC with the prepared values */
|
||||
|
|
@ -1001,6 +1008,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
temp = CURSOR_MODE_DISABLE;
|
||||
addr = 0;
|
||||
bo = NULL;
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
goto finish;
|
||||
}
|
||||
|
||||
|
|
@ -1023,18 +1031,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
}
|
||||
|
||||
/* we only need to pin inside GTT if cursor is non-phy */
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
if (!dev_priv->cursor_needs_physical) {
|
||||
ret = i915_gem_object_pin(bo, PAGE_SIZE);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to pin cursor bo\n");
|
||||
goto fail;
|
||||
goto fail_locked;
|
||||
}
|
||||
addr = obj_priv->gtt_offset;
|
||||
} else {
|
||||
ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to attach phys object\n");
|
||||
goto fail;
|
||||
goto fail_locked;
|
||||
}
|
||||
addr = obj_priv->phys_obj->handle->busaddr;
|
||||
}
|
||||
|
|
@ -1054,10 +1063,9 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
|
||||
} else
|
||||
i915_gem_object_unpin(intel_crtc->cursor_bo);
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(intel_crtc->cursor_bo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
}
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
||||
intel_crtc->cursor_addr = addr;
|
||||
intel_crtc->cursor_bo = bo;
|
||||
|
|
@ -1065,6 +1073,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
|
|||
return 0;
|
||||
fail:
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
fail_locked:
|
||||
drm_gem_object_unreference(bo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return ret;
|
||||
|
|
@ -1292,7 +1301,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
|
|||
}
|
||||
|
||||
/* XXX: Handle the 100Mhz refclk */
|
||||
i9xx_clock(96000, &clock);
|
||||
intel_clock(96000, &clock);
|
||||
} else {
|
||||
bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
|
||||
|
||||
|
|
@ -1304,9 +1313,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
|
|||
if ((dpll & PLL_REF_INPUT_MASK) ==
|
||||
PLLB_REF_INPUT_SPREADSPECTRUMIN) {
|
||||
/* XXX: might not be 66MHz */
|
||||
i8xx_clock(66000, &clock);
|
||||
intel_clock(66000, &clock);
|
||||
} else
|
||||
i8xx_clock(48000, &clock);
|
||||
intel_clock(48000, &clock);
|
||||
} else {
|
||||
if (dpll & PLL_P1_DIVIDE_BY_TWO)
|
||||
clock.p1 = 2;
|
||||
|
|
@ -1319,7 +1328,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
|
|||
else
|
||||
clock.p2 = 2;
|
||||
|
||||
i8xx_clock(48000, &clock);
|
||||
intel_clock(48000, &clock);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1598,7 +1607,9 @@ intel_user_framebuffer_create(struct drm_device *dev,
|
|||
|
||||
ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
|
||||
if (ret) {
|
||||
mutex_lock(&dev->struct_mutex);
|
||||
drm_gem_object_unreference(obj);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo);
|
||||
if (ret) {
|
||||
DRM_ERROR("failed to allocate fb.\n");
|
||||
goto out_unref;
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
|
||||
|
|
@ -484,7 +484,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
info = framebuffer_alloc(sizeof(struct intelfb_par), device);
|
||||
if (!info) {
|
||||
ret = -ENOMEM;
|
||||
goto out_unref;
|
||||
goto out_unpin;
|
||||
}
|
||||
|
||||
par = info->par;
|
||||
|
|
@ -513,7 +513,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
size);
|
||||
if (!info->screen_base) {
|
||||
ret = -ENOSPC;
|
||||
goto out_unref;
|
||||
goto out_unpin;
|
||||
}
|
||||
info->screen_size = size;
|
||||
|
||||
|
|
@ -608,6 +608,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
|
|||
mutex_unlock(&dev->struct_mutex);
|
||||
return 0;
|
||||
|
||||
out_unpin:
|
||||
i915_gem_object_unpin(fbo);
|
||||
out_unref:
|
||||
drm_gem_object_unreference(fbo);
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
|
|
|||
|
|
@ -481,8 +481,6 @@ void intel_lvds_init(struct drm_device *dev)
|
|||
if (dev_priv->panel_fixed_mode) {
|
||||
dev_priv->panel_fixed_mode->type |=
|
||||
DRM_MODE_TYPE_PREFERRED;
|
||||
drm_mode_probed_add(connector,
|
||||
dev_priv->panel_fixed_mode);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
|
|||
|
||||
#define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
|
||||
/** Mapping of command numbers to names, for debug output */
|
||||
const static struct _sdvo_cmd_name {
|
||||
static const struct _sdvo_cmd_name {
|
||||
u8 cmd;
|
||||
char *name;
|
||||
} sdvo_cmd_names[] = {
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ struct tv_mode {
|
|||
* These values account for -1s required.
|
||||
*/
|
||||
|
||||
const static struct tv_mode tv_modes[] = {
|
||||
static const struct tv_mode tv_modes[] = {
|
||||
{
|
||||
.name = "NTSC-M",
|
||||
.clock = 107520,
|
||||
|
|
|
|||
|
|
@ -557,8 +557,10 @@ static int radeon_do_engine_reset(struct drm_device * dev)
|
|||
}
|
||||
|
||||
static void radeon_cp_init_ring_buffer(struct drm_device * dev,
|
||||
drm_radeon_private_t * dev_priv)
|
||||
drm_radeon_private_t *dev_priv,
|
||||
struct drm_file *file_priv)
|
||||
{
|
||||
struct drm_radeon_master_private *master_priv;
|
||||
u32 ring_start, cur_read_ptr;
|
||||
u32 tmp;
|
||||
|
||||
|
|
@ -677,6 +679,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
|
|||
dev_priv->scratch[2] = 0;
|
||||
RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
|
||||
|
||||
/* reset sarea copies of these */
|
||||
master_priv = file_priv->master->driver_priv;
|
||||
if (master_priv->sarea_priv) {
|
||||
master_priv->sarea_priv->last_frame = 0;
|
||||
master_priv->sarea_priv->last_dispatch = 0;
|
||||
master_priv->sarea_priv->last_clear = 0;
|
||||
}
|
||||
|
||||
radeon_do_wait_for_idle(dev_priv);
|
||||
|
||||
/* Sync everything up */
|
||||
|
|
@ -1215,7 +1225,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
|
|||
}
|
||||
|
||||
radeon_cp_load_microcode(dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
|
||||
|
||||
dev_priv->last_buf = 0;
|
||||
|
||||
|
|
@ -1281,7 +1291,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
|
|||
*
|
||||
* Charl P. Botha <http://cpbotha.net>
|
||||
*/
|
||||
static int radeon_do_resume_cp(struct drm_device * dev)
|
||||
static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
|
||||
{
|
||||
drm_radeon_private_t *dev_priv = dev->dev_private;
|
||||
|
||||
|
|
@ -1304,7 +1314,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
|
|||
}
|
||||
|
||||
radeon_cp_load_microcode(dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv);
|
||||
radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
|
||||
|
||||
radeon_do_engine_reset(dev);
|
||||
radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
|
||||
|
|
@ -1479,8 +1489,7 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
|
|||
*/
|
||||
int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
{
|
||||
|
||||
return radeon_do_resume_cp(dev);
|
||||
return radeon_do_resume_cp(dev, file_priv);
|
||||
}
|
||||
|
||||
int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
|
||||
|
|
|
|||
|
|
@ -1300,7 +1300,13 @@ static const struct hid_device_id hid_blacklist[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
|
||||
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
|
||||
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
|
||||
|
|
@ -1605,6 +1611,7 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3) },
|
||||
|
|
@ -1612,10 +1619,6 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
|
||||
|
|
@ -1626,8 +1629,6 @@ static const struct hid_device_id hid_ignore_list[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -348,6 +348,9 @@
|
|||
#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
|
||||
#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
|
||||
|
||||
#define USB_VENDOR_ID_POWERCOM 0x0d9f
|
||||
#define USB_DEVICE_ID_POWERCOM_UPS 0x0002
|
||||
|
||||
#define USB_VENDOR_ID_SAITEK 0x06a3
|
||||
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
|
||||
|
||||
|
|
|
|||
|
|
@ -267,8 +267,10 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
|
|||
default:
|
||||
{
|
||||
struct hid_device *hid = dev->hid;
|
||||
if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
|
||||
return -EINVAL;
|
||||
if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) {
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
|
||||
int len;
|
||||
|
|
@ -277,8 +279,9 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
|
|||
len = strlen(hid->name) + 1;
|
||||
if (len > _IOC_SIZE(cmd))
|
||||
len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(user_arg, hid->name, len) ?
|
||||
ret = copy_to_user(user_arg, hid->name, len) ?
|
||||
-EFAULT : len;
|
||||
break;
|
||||
}
|
||||
|
||||
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
|
||||
|
|
@ -288,12 +291,13 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
|
|||
len = strlen(hid->phys) + 1;
|
||||
if (len > _IOC_SIZE(cmd))
|
||||
len = _IOC_SIZE(cmd);
|
||||
return copy_to_user(user_arg, hid->phys, len) ?
|
||||
ret = copy_to_user(user_arg, hid->phys, len) ?
|
||||
-EFAULT : len;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = -ENOTTY;
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
unlock_kernel();
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -543,8 +543,8 @@ config SENSORS_LM90
|
|||
help
|
||||
If you say yes here you get support for National Semiconductor LM90,
|
||||
LM86, LM89 and LM99, Analog Devices ADM1032 and ADT7461, and Maxim
|
||||
MAX6646, MAX6647, MAX6649, MAX6657, MAX6658, MAX6659, MAX6680 and
|
||||
MAX6681 sensor chips.
|
||||
MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659,
|
||||
MAX6680, MAX6681 and MAX6692 sensor chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called lm90.
|
||||
|
|
|
|||
|
|
@ -760,8 +760,11 @@ static int abituguru3_read_increment_offset(struct abituguru3_data *data,
|
|||
|
||||
for (i = 0; i < offset_count; i++)
|
||||
if ((x = abituguru3_read(data, bank, offset + i, count,
|
||||
buf + i * count)) != count)
|
||||
return i * count + (i && (x < 0)) ? 0 : x;
|
||||
buf + i * count)) != count) {
|
||||
if (x < 0)
|
||||
return x;
|
||||
return i * count + x;
|
||||
}
|
||||
|
||||
return i * count;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1872,7 +1872,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
|
|||
|
||||
devid = superio_inw(sioaddr, SIO_REG_MANID);
|
||||
if (devid != SIO_FINTEK_ID) {
|
||||
printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
|
||||
pr_debug(DRVNAME ": Not a Fintek device\n");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
@ -1932,7 +1932,7 @@ static int __init f71882fg_device_add(unsigned short address,
|
|||
res.name = f71882fg_pdev->name;
|
||||
err = acpi_check_resource_conflict(&res);
|
||||
if (err)
|
||||
return err;
|
||||
goto exit_device_put;
|
||||
|
||||
err = platform_device_add_resources(f71882fg_pdev, &res, 1);
|
||||
if (err) {
|
||||
|
|
|
|||
|
|
@ -617,7 +617,7 @@ static void f75375_init(struct i2c_client *client, struct f75375_data *data,
|
|||
static int f75375_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct f75375_data *data = i2c_get_clientdata(client);
|
||||
struct f75375_data *data;
|
||||
struct f75375s_platform_data *f75375s_pdata = client->dev.platform_data;
|
||||
int err;
|
||||
|
||||
|
|
|
|||
|
|
@ -166,6 +166,18 @@ static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
|
|||
}, \
|
||||
.driver_data = &lis3lv02d_axis_##_axis \
|
||||
}
|
||||
|
||||
#define AXIS_DMI_MATCH2(_ident, _class1, _name1, \
|
||||
_class2, _name2, \
|
||||
_axis) { \
|
||||
.ident = _ident, \
|
||||
.callback = lis3lv02d_dmi_matched, \
|
||||
.matches = { \
|
||||
DMI_MATCH(DMI_##_class1, _name1), \
|
||||
DMI_MATCH(DMI_##_class2, _name2), \
|
||||
}, \
|
||||
.driver_data = &lis3lv02d_axis_##_axis \
|
||||
}
|
||||
static struct dmi_system_id lis3lv02d_dmi_ids[] = {
|
||||
/* product names are truncated to match all kinds of a same model */
|
||||
AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
|
||||
|
|
@ -179,6 +191,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
|
|||
AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
|
||||
AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
|
||||
AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted),
|
||||
/* Intel-based HP Pavilion dv5 */
|
||||
AXIS_DMI_MATCH2("HPDV5_I",
|
||||
PRODUCT_NAME, "HP Pavilion dv5",
|
||||
BOARD_NAME, "3603",
|
||||
x_inverted),
|
||||
/* AMD-based HP Pavilion dv5 */
|
||||
AXIS_DMI_MATCH2("HPDV5_A",
|
||||
PRODUCT_NAME, "HP Pavilion dv5",
|
||||
BOARD_NAME, "3600",
|
||||
y_inverted),
|
||||
{ NULL, }
|
||||
/* Laptop models without axis info (yet):
|
||||
* "NC6910" "HP Compaq 6910"
|
||||
|
|
@ -213,9 +235,49 @@ static struct delayed_led_classdev hpled_led = {
|
|||
.set_brightness = hpled_set,
|
||||
};
|
||||
|
||||
static acpi_status
|
||||
lis3lv02d_get_resource(struct acpi_resource *resource, void *context)
|
||||
{
|
||||
if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
|
||||
struct acpi_resource_extended_irq *irq;
|
||||
u32 *device_irq = context;
|
||||
|
||||
irq = &resource->data.extended_irq;
|
||||
*device_irq = irq->interrupts[0];
|
||||
}
|
||||
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static void lis3lv02d_enum_resources(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
|
||||
lis3lv02d_get_resource, &adev.irq);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
|
||||
}
|
||||
|
||||
static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
|
||||
{
|
||||
u8 lo, hi;
|
||||
|
||||
adev.read(handle, reg - 1, &lo);
|
||||
adev.read(handle, reg, &hi);
|
||||
/* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
|
||||
return (s16)((hi << 8) | lo);
|
||||
}
|
||||
|
||||
static s16 lis3lv02d_read_8(acpi_handle handle, int reg)
|
||||
{
|
||||
s8 lo;
|
||||
adev.read(handle, reg, &lo);
|
||||
return lo;
|
||||
}
|
||||
|
||||
static int lis3lv02d_add(struct acpi_device *device)
|
||||
{
|
||||
u8 val;
|
||||
int ret;
|
||||
|
||||
if (!device)
|
||||
|
|
@ -229,10 +291,22 @@ static int lis3lv02d_add(struct acpi_device *device)
|
|||
strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
|
||||
device->driver_data = &adev;
|
||||
|
||||
lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val);
|
||||
if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) {
|
||||
lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami);
|
||||
switch (adev.whoami) {
|
||||
case LIS_DOUBLE_ID:
|
||||
printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
|
||||
adev.read_data = lis3lv02d_read_16;
|
||||
adev.mdps_max_val = 2048;
|
||||
break;
|
||||
case LIS_SINGLE_ID:
|
||||
printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
|
||||
adev.read_data = lis3lv02d_read_8;
|
||||
adev.mdps_max_val = 128;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR DRIVER_NAME
|
||||
": Accelerometer chip not LIS3LV02D{L,Q}\n");
|
||||
": unknown sensor type 0x%X\n", adev.whoami);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* If possible use a "standard" axes order */
|
||||
|
|
@ -247,6 +321,9 @@ static int lis3lv02d_add(struct acpi_device *device)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* obtain IRQ number of our device from ACPI */
|
||||
lis3lv02d_enum_resources(adev.device);
|
||||
|
||||
ret = lis3lv02d_init_device(&adev);
|
||||
if (ret) {
|
||||
flush_work(&hpled_led.work);
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue