From 5b7c4cabbb65f5c469464da6c5f614cbd7f730f2 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Tue, 21 Feb 2023 18:24:12 -0800 Subject: Merge tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next Pull networking updates from Jakub Kicinski: "Core: - Add dedicated kmem_cache for typical/small skb->head, avoid having to access struct page at kfree time, and improve memory use. - Introduce sysctl to set default RPS configuration for new netdevs. - Define Netlink protocol specification format which can be used to describe messages used by each family and auto-generate parsers. Add tools for generating kernel data structures and uAPI headers. - Expose all net/core sysctls inside netns. - Remove 4s sleep in netpoll if carrier is instantly detected on boot. - Add configurable limit of MDB entries per port, and port-vlan. - Continue populating drop reasons throughout the stack. - Retire a handful of legacy Qdiscs and classifiers. Protocols: - Support IPv4 big TCP (TSO frames larger than 64kB). - Add IP_LOCAL_PORT_RANGE socket option, to control local port range on socket by socket basis. - Track and report in procfs number of MPTCP sockets used. - Support mixing IPv4 and IPv6 flows in the in-kernel MPTCP path manager. - IPv6: don't check net.ipv6.route.max_size and rely on garbage collection to free memory (similarly to IPv4). - Support Penultimate Segment Pop (PSP) flavor in SRv6 (RFC8986). - ICMP: add per-rate limit counters. - Add support for user scanning requests in ieee802154. - Remove static WEP support. - Support minimal Wi-Fi 7 Extremely High Throughput (EHT) rate reporting. - WiFi 7 EHT channel puncturing support (client & AP). BPF: - Add a rbtree data structure following the "next-gen data structure" precedent set by recently added linked list, that is, by using kfunc + kptr instead of adding a new BPF map type. - Expose XDP hints via kfuncs with initial support for RX hash and timestamp metadata. - Add BPF_F_NO_TUNNEL_KEY extension to bpf_skb_set_tunnel_key to better support decap on GRE tunnel devices not operating in collect metadata. - Improve x86 JIT's codegen for PROBE_MEM runtime error checks. - Remove the need for trace_printk_lock for bpf_trace_printk and bpf_trace_vprintk helpers. - Extend libbpf's bpf_tracing.h support for tracing arguments of kprobes/uprobes and syscall as a special case. - Significantly reduce the search time for module symbols by livepatch and BPF. - Enable cpumasks to be used as kptrs, which is useful for tracing programs tracking which tasks end up running on which CPUs in different time intervals. - Add support for BPF trampoline on s390x and riscv64. - Add capability to export the XDP features supported by the NIC. - Add __bpf_kfunc tag for marking kernel functions as kfuncs. - Add cgroup.memory=nobpf kernel parameter option to disable BPF memory accounting for container environments. Netfilter: - Remove the CLUSTERIP target. It has been marked as obsolete for years, and we still have WARN splats wrt races of the out-of-band /proc interface installed by this target. - Add 'destroy' commands to nf_tables. They are identical to the existing 'delete' commands, but do not return an error if the referenced object (set, chain, rule...) did not exist. Driver API: - Improve cpumask_local_spread() locality to help NICs set the right IRQ affinity on AMD platforms. - Separate C22 and C45 MDIO bus transactions more clearly. - Introduce new DCB table to control DSCP rewrite on egress. - Support configuration of Physical Layer Collision Avoidance (PLCA) Reconciliation Sublayer (RS) (802.3cg-2019). Modern version of shared medium Ethernet. - Support for MAC Merge layer (IEEE 802.3-2018 clause 99). Allowing preemption of low priority frames by high priority frames. - Add support for controlling MACSec offload using netlink SET. - Rework devlink instance refcounts to allow registration and de-registration under the instance lock. Split the code into multiple files, drop some of the unnecessarily granular locks and factor out common parts of netlink operation handling. - Add TX frame aggregation parameters (for USB drivers). - Add a new attr TCA_EXT_WARN_MSG to report TC (offload) warning messages with notifications for debug. - Allow offloading of UDP NEW connections via act_ct. - Add support for per action HW stats in TC. - Support hardware miss to TC action (continue processing in SW from a specific point in the action chain). - Warn if old Wireless Extension user space interface is used with modern cfg80211/mac80211 drivers. Do not support Wireless Extensions for Wi-Fi 7 devices at all. Everyone should switch to using nl80211 interface instead. - Improve the CAN bit timing configuration. Use extack to return error messages directly to user space, update the SJW handling, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. New hardware / drivers: - Ethernet: - nVidia BlueField-3 support (control traffic driver) - Ethernet support for imx93 SoCs - Motorcomm yt8531 gigabit Ethernet PHY - onsemi NCN26000 10BASE-T1S PHY (with support for PLCA) - Microchip LAN8841 PHY (incl. cable diagnostics and PTP) - Amlogic gxl MDIO mux - WiFi: - RealTek RTL8188EU (rtl8xxxu) - Qualcomm Wi-Fi 7 devices (ath12k) - CAN: - Renesas R-Car V4H Drivers: - Bluetooth: - Set Per Platform Antenna Gain (PPAG) for Intel controllers. - Ethernet NICs: - Intel (1G, igc): - support TSN / Qbv / packet scheduling features of i226 model - Intel (100G, ice): - use GNSS subsystem instead of TTY - multi-buffer XDP support - extend support for GPIO pins to E823 devices - nVidia/Mellanox: - update the shared buffer configuration on PFC commands - implement PTP adjphase function for HW offset control - TC support for Geneve and GRE with VF tunnel offload - more efficient crypto key management method - multi-port eswitch support - Netronome/Corigine: - add DCB IEEE support - support IPsec offloading for NFP3800 - Freescale/NXP (enetc): - support XDP_REDIRECT for XDP non-linear buffers - improve reconfig, avoid link flap and waiting for idle - support MAC Merge layer - Other NICs: - sfc/ef100: add basic devlink support for ef100 - ionic: rx_push mode operation (writing descriptors via MMIO) - bnxt: use the auxiliary bus abstraction for RDMA - r8169: disable ASPM and reset bus in case of tx timeout - cpsw: support QSGMII mode for J721e CPSW9G - cpts: support pulse-per-second output - ngbe: add an mdio bus driver - usbnet: optimize usbnet_bh() by avoiding unnecessary queuing - r8152: handle devices with FW with NCM support - amd-xgbe: support 10Mbps, 2.5GbE speeds and rx-adaptation - virtio-net: support multi buffer XDP - virtio/vsock: replace virtio_vsock_pkt with sk_buff - tsnep: XDP support - Ethernet high-speed switches: - nVidia/Mellanox (mlxsw): - add support for latency TLV (in FW control messages) - Microchip (sparx5): - separate explicit and implicit traffic forwarding rules, make the implicit rules always active - add support for egress DSCP rewrite - IS0 VCAP support (Ingress Classification) - IS2 VCAP filters (protos, L3 addrs, L4 ports, flags, ToS etc.) - ES2 VCAP support (Egress Access Control) - support for Per-Stream Filtering and Policing (802.1Q, 8.6.5.1) - Ethernet embedded switches: - Marvell (mv88e6xxx): - add MAB (port auth) offload support - enable PTP receive for mv88e6390 - NXP (ocelot): - support MAC Merge layer - support for the the vsc7512 internal copper phys - Microchip: - lan9303: convert to PHYLINK - lan966x: support TC flower filter statistics - lan937x: PTP support for KSZ9563/KSZ8563 and LAN937x - lan937x: support Credit Based Shaper configuration - ksz9477: support Energy Efficient Ethernet - other: - qca8k: convert to regmap read/write API, use bulk operations - rswitch: Improve TX timestamp accuracy - Intel WiFi (iwlwifi): - EHT (Wi-Fi 7) rate reporting - STEP equalizer support: transfer some STEP (connection to radio on platforms with integrated wifi) related parameters from the BIOS to the firmware. - Qualcomm 802.11ax WiFi (ath11k): - IPQ5018 support - Fine Timing Measurement (FTM) responder role support - channel 177 support - MediaTek WiFi (mt76): - per-PHY LED support - mt7996: EHT (Wi-Fi 7) support - Wireless Ethernet Dispatch (WED) reset support - switch to using page pool allocator - RealTek WiFi (rtw89): - support new version of Bluetooth co-existance - Mobile: - rmnet: support TX aggregation" * tag 'net-next-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net-next: (1872 commits) page_pool: add a comment explaining the fragment counter usage net: ethtool: fix __ethtool_dev_mm_supported() implementation ethtool: pse-pd: Fix double word in comments xsk: add linux/vmalloc.h to xsk.c sefltests: netdevsim: wait for devlink instance after netns removal selftest: fib_tests: Always cleanup before exit net/mlx5e: Align IPsec ASO result memory to be as required by hardware net/mlx5e: TC, Set CT miss to the specific ct action instance net/mlx5e: Rename CHAIN_TO_REG to MAPPED_OBJ_TO_REG net/mlx5: Refactor tc miss handling to a single function net/mlx5: Kconfig: Make tc offload depend on tc skb extension net/sched: flower: Support hardware miss to tc action net/sched: flower: Move filter handle initialization earlier net/sched: cls_api: Support hardware miss to tc action net/sched: Rename user cookie and act cookie sfc: fix builds without CONFIG_RTC_LIB sfc: clean up some inconsistent indentings net/mlx4_en: Introduce flexible array to silence overflow warning net: lan966x: Fix possible deadlock inside PTP net/ulp: Remove redundant ->clone() test in inet_clone_ulp(). ... --- drivers/ata/pata_serverworks.c | 494 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 494 insertions(+) create mode 100644 drivers/ata/pata_serverworks.c (limited to 'drivers/ata/pata_serverworks.c') diff --git a/drivers/ata/pata_serverworks.c b/drivers/ata/pata_serverworks.c new file mode 100644 index 000000000..c0bc4af0d --- /dev/null +++ b/drivers/ata/pata_serverworks.c @@ -0,0 +1,494 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * pata_serverworks.c - Serverworks PATA for new ATA layer + * (C) 2005 Red Hat Inc + * (C) 2010 Bartlomiej Zolnierkiewicz + * + * based upon + * + * serverworks.c + * + * Copyright (C) 1998-2000 Michel Aubry + * Copyright (C) 1998-2000 Andrzej Krzysztofowicz + * Copyright (C) 1998-2000 Andre Hedrick + * Portions copyright (c) 2001 Sun Microsystems + * + * + * RCC/ServerWorks IDE driver for Linux + * + * OSB4: `Open South Bridge' IDE Interface (fn 1) + * supports UDMA mode 2 (33 MB/s) + * + * CSB5: `Champion South Bridge' IDE Interface (fn 1) + * all revisions support UDMA mode 4 (66 MB/s) + * revision A2.0 and up support UDMA mode 5 (100 MB/s) + * + * *** The CSB5 does not provide ANY register *** + * *** to detect 80-conductor cable presence. *** + * + * CSB6: `Champion South Bridge' IDE Interface (optional: third channel) + * + * Documentation: + * Available under NDA only. Errata info very hard to get. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "pata_serverworks" +#define DRV_VERSION "0.4.3" + +#define SVWKS_CSB5_REVISION_NEW 0x92 /* min PCI_REVISION_ID for UDMA5 (A2.0) */ +#define SVWKS_CSB6_REVISION 0xa0 /* min PCI_REVISION_ID for UDMA4 (A1.0) */ + +/* Seagate Barracuda ATA IV Family drives in UDMA mode 5 + * can overrun their FIFOs when used with the CSB5 */ + +static const char *csb_bad_ata100[] = { + "ST320011A", + "ST340016A", + "ST360021A", + "ST380021A", + NULL +}; + +/** + * oem_cable - Dell/Sun serverworks cable detection + * @ap: ATA port to do cable detect + * + * Dell PowerEdge and Sun Cobalt 'Alpine' hide the 40/80 pin select + * for their interfaces in the top two bits of the subsystem ID. + */ + +static int oem_cable(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + if (pdev->subsystem_device & (1 << (ap->port_no + 14))) + return ATA_CBL_PATA80; + return ATA_CBL_PATA40; +} + +struct sv_cable_table { + int device; + int subvendor; + int (*cable_detect)(struct ata_port *ap); +}; + +static struct sv_cable_table cable_detect[] = { + { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_DELL, oem_cable }, + { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_VENDOR_ID_DELL, oem_cable }, + { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_VENDOR_ID_SUN, oem_cable }, + { PCI_DEVICE_ID_SERVERWORKS_OSB4IDE, PCI_ANY_ID, ata_cable_40wire }, + { PCI_DEVICE_ID_SERVERWORKS_CSB5IDE, PCI_ANY_ID, ata_cable_unknown }, + { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE, PCI_ANY_ID, ata_cable_unknown }, + { PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2, PCI_ANY_ID, ata_cable_unknown }, + { PCI_DEVICE_ID_SERVERWORKS_HT1000IDE, PCI_ANY_ID, ata_cable_unknown }, + { } +}; + +/** + * serverworks_cable_detect - cable detection + * @ap: ATA port + * + * Perform cable detection according to the device and subvendor + * identifications + */ + +static int serverworks_cable_detect(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + struct sv_cable_table *cb = cable_detect; + + while(cb->device) { + if (cb->device == pdev->device && + (cb->subvendor == pdev->subsystem_vendor || + cb->subvendor == PCI_ANY_ID)) { + return cb->cable_detect(ap); + } + cb++; + } + + BUG(); + return -1; /* kill compiler warning */ +} + +/** + * serverworks_is_csb - Check for CSB or OSB + * @pdev: PCI device to check + * + * Returns true if the device being checked is known to be a CSB + * series device. + */ + +static u8 serverworks_is_csb(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: + return 1; + default: + break; + } + return 0; +} + +/** + * serverworks_osb4_filter - mode selection filter + * @adev: ATA device + * @mask: Mask of proposed modes + * + * Filter the offered modes for the device to apply controller + * specific rules. OSB4 requires no UDMA for disks due to a FIFO + * bug we hit. + */ + +static unsigned int serverworks_osb4_filter(struct ata_device *adev, unsigned int mask) +{ + if (adev->class == ATA_DEV_ATA) + mask &= ~ATA_MASK_UDMA; + return mask; +} + + +/** + * serverworks_csb_filter - mode selection filter + * @adev: ATA device + * @mask: Mask of proposed modes + * + * Check the blacklist and disable UDMA5 if matched + */ + +static unsigned int serverworks_csb_filter(struct ata_device *adev, unsigned int mask) +{ + const char *p; + char model_num[ATA_ID_PROD_LEN + 1]; + int i; + + /* Disk, UDMA */ + if (adev->class != ATA_DEV_ATA) + return mask; + + /* Actually do need to check */ + ata_id_c_string(adev->id, model_num, ATA_ID_PROD, sizeof(model_num)); + + for (i = 0; (p = csb_bad_ata100[i]) != NULL; i++) { + if (!strcmp(p, model_num)) + mask &= ~(0xE0 << ATA_SHIFT_UDMA); + } + return mask; +} + +/** + * serverworks_set_piomode - set initial PIO mode data + * @ap: ATA interface + * @adev: ATA device + * + * Program the OSB4/CSB5 timing registers for PIO. The PIO register + * load is done as a simple lookup. + */ +static void serverworks_set_piomode(struct ata_port *ap, struct ata_device *adev) +{ + static const u8 pio_mode[] = { 0x5d, 0x47, 0x34, 0x22, 0x20 }; + int offset = 1 + 2 * ap->port_no - adev->devno; + int devbits = (2 * ap->port_no + adev->devno) * 4; + u16 csb5_pio; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + int pio = adev->pio_mode - XFER_PIO_0; + + pci_write_config_byte(pdev, 0x40 + offset, pio_mode[pio]); + + /* The OSB4 just requires the timing but the CSB series want the + mode number as well */ + if (serverworks_is_csb(pdev)) { + pci_read_config_word(pdev, 0x4A, &csb5_pio); + csb5_pio &= ~(0x0F << devbits); + pci_write_config_word(pdev, 0x4A, csb5_pio | (pio << devbits)); + } +} + +/** + * serverworks_set_dmamode - set initial DMA mode data + * @ap: ATA interface + * @adev: ATA device + * + * Program the MWDMA/UDMA modes for the serverworks OSB4/CSB5 + * chipset. The MWDMA mode values are pulled from a lookup table + * while the chipset uses mode number for UDMA. + */ + +static void serverworks_set_dmamode(struct ata_port *ap, struct ata_device *adev) +{ + static const u8 dma_mode[] = { 0x77, 0x21, 0x20 }; + int offset = 1 + 2 * ap->port_no - adev->devno; + int devbits = 2 * ap->port_no + adev->devno; + u8 ultra; + u8 ultra_cfg; + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + + pci_read_config_byte(pdev, 0x54, &ultra_cfg); + pci_read_config_byte(pdev, 0x56 + ap->port_no, &ultra); + ultra &= ~(0x0F << (adev->devno * 4)); + + if (adev->dma_mode >= XFER_UDMA_0) { + pci_write_config_byte(pdev, 0x44 + offset, 0x20); + + ultra |= (adev->dma_mode - XFER_UDMA_0) + << (adev->devno * 4); + ultra_cfg |= (1 << devbits); + } else { + pci_write_config_byte(pdev, 0x44 + offset, + dma_mode[adev->dma_mode - XFER_MW_DMA_0]); + ultra_cfg &= ~(1 << devbits); + } + pci_write_config_byte(pdev, 0x56 + ap->port_no, ultra); + pci_write_config_byte(pdev, 0x54, ultra_cfg); +} + +static struct scsi_host_template serverworks_osb4_sht = { + ATA_BASE_SHT(DRV_NAME), + .sg_tablesize = LIBATA_DUMB_MAX_PRD, + .dma_boundary = ATA_DMA_BOUNDARY, +}; + +static struct scsi_host_template serverworks_csb_sht = { + ATA_BMDMA_SHT(DRV_NAME), +}; + +static struct ata_port_operations serverworks_osb4_port_ops = { + .inherits = &ata_bmdma_port_ops, + .qc_prep = ata_bmdma_dumb_qc_prep, + .cable_detect = serverworks_cable_detect, + .mode_filter = serverworks_osb4_filter, + .set_piomode = serverworks_set_piomode, + .set_dmamode = serverworks_set_dmamode, +}; + +static struct ata_port_operations serverworks_csb_port_ops = { + .inherits = &serverworks_osb4_port_ops, + .qc_prep = ata_bmdma_qc_prep, + .mode_filter = serverworks_csb_filter, +}; + +static int serverworks_fixup_osb4(struct pci_dev *pdev) +{ + u32 reg; + struct pci_dev *isa_dev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_OSB4, NULL); + if (isa_dev) { + pci_read_config_dword(isa_dev, 0x64, ®); + reg &= ~0x00002000; /* disable 600ns interrupt mask */ + if (!(reg & 0x00004000)) + dev_info(&pdev->dev, "UDMA not BIOS enabled.\n"); + reg |= 0x00004000; /* enable UDMA/33 support */ + pci_write_config_dword(isa_dev, 0x64, reg); + pci_dev_put(isa_dev); + return 0; + } + dev_warn(&pdev->dev, "Unable to find bridge.\n"); + return -ENODEV; +} + +static int serverworks_fixup_csb(struct pci_dev *pdev) +{ + u8 btr; + + /* Third Channel Test */ + if (!(PCI_FUNC(pdev->devfn) & 1)) { + struct pci_dev * findev = NULL; + u32 reg4c = 0; + findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB5, NULL); + if (findev) { + pci_read_config_dword(findev, 0x4C, ®4c); + reg4c &= ~0x000007FF; + reg4c |= 0x00000040; + reg4c |= 0x00000020; + pci_write_config_dword(findev, 0x4C, reg4c); + pci_dev_put(findev); + } + } else { + struct pci_dev * findev = NULL; + u8 reg41 = 0; + + findev = pci_get_device(PCI_VENDOR_ID_SERVERWORKS, + PCI_DEVICE_ID_SERVERWORKS_CSB6, NULL); + if (findev) { + pci_read_config_byte(findev, 0x41, ®41); + reg41 &= ~0x40; + pci_write_config_byte(findev, 0x41, reg41); + pci_dev_put(findev); + } + } + /* setup the UDMA Control register + * + * 1. clear bit 6 to enable DMA + * 2. enable DMA modes with bits 0-1 + * 00 : legacy + * 01 : udma2 + * 10 : udma2/udma4 + * 11 : udma2/udma4/udma5 + */ + pci_read_config_byte(pdev, 0x5A, &btr); + btr &= ~0x40; + if (!(PCI_FUNC(pdev->devfn) & 1)) + btr |= 0x2; + else + btr |= (pdev->revision >= SVWKS_CSB5_REVISION_NEW) ? 0x3 : 0x2; + pci_write_config_byte(pdev, 0x5A, btr); + + return btr; +} + +static void serverworks_fixup_ht1000(struct pci_dev *pdev) +{ + u8 btr; + /* Setup HT1000 SouthBridge Controller - Single Channel Only */ + pci_read_config_byte(pdev, 0x5A, &btr); + btr &= ~0x40; + btr |= 0x3; + pci_write_config_byte(pdev, 0x5A, btr); +} + +static int serverworks_fixup(struct pci_dev *pdev) +{ + int rc = 0; + + /* Force master latency timer to 64 PCI clocks */ + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x40); + + switch (pdev->device) { + case PCI_DEVICE_ID_SERVERWORKS_OSB4IDE: + rc = serverworks_fixup_osb4(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_CSB5IDE: + ata_pci_bmdma_clear_simplex(pdev); + fallthrough; + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE: + case PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2: + rc = serverworks_fixup_csb(pdev); + break; + case PCI_DEVICE_ID_SERVERWORKS_HT1000IDE: + serverworks_fixup_ht1000(pdev); + break; + } + + return rc; +} + +static int serverworks_init_one(struct pci_dev *pdev, const struct pci_device_id *id) +{ + static const struct ata_port_info info[4] = { + { /* OSB4 */ + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA2, + .port_ops = &serverworks_osb4_port_ops + }, { /* OSB4 no UDMA */ + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + /* No UDMA */ + .port_ops = &serverworks_osb4_port_ops + }, { /* CSB5 */ + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA4, + .port_ops = &serverworks_csb_port_ops + }, { /* CSB5 - later revisions*/ + .flags = ATA_FLAG_SLAVE_POSS, + .pio_mask = ATA_PIO4, + .mwdma_mask = ATA_MWDMA2, + .udma_mask = ATA_UDMA5, + .port_ops = &serverworks_csb_port_ops + } + }; + const struct ata_port_info *ppi[] = { &info[id->driver_data], NULL }; + struct scsi_host_template *sht = &serverworks_csb_sht; + int rc; + + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + rc = serverworks_fixup(pdev); + + /* OSB4 : South Bridge and IDE */ + if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_OSB4IDE) { + /* Select non UDMA capable OSB4 if we can't do fixups */ + if (rc < 0) + ppi[0] = &info[1]; + sht = &serverworks_osb4_sht; + } + /* setup CSB5/CSB6 : South Bridge and IDE option RAID */ + else if ((pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB5IDE) || + (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE) || + (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2)) { + + /* If the returned btr is the newer revision then + select the right info block */ + if (rc == 3) + ppi[0] = &info[3]; + + /* Is this the 3rd channel CSB6 IDE ? */ + if (pdev->device == PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2) + ppi[1] = &ata_dummy_port_info; + } + + return ata_pci_bmdma_init_one(pdev, ppi, sht, NULL, 0); +} + +#ifdef CONFIG_PM_SLEEP +static int serverworks_reinit_one(struct pci_dev *pdev) +{ + struct ata_host *host = pci_get_drvdata(pdev); + int rc; + + rc = ata_pci_device_do_resume(pdev); + if (rc) + return rc; + + (void)serverworks_fixup(pdev); + + ata_host_resume(host); + return 0; +} +#endif + +static const struct pci_device_id serverworks[] = { + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_OSB4IDE), 0}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB5IDE), 2}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE), 2}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2), 2}, + { PCI_VDEVICE(SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000IDE), 2}, + + { }, +}; + +static struct pci_driver serverworks_pci_driver = { + .name = DRV_NAME, + .id_table = serverworks, + .probe = serverworks_init_one, + .remove = ata_pci_remove_one, +#ifdef CONFIG_PM_SLEEP + .suspend = ata_pci_device_suspend, + .resume = serverworks_reinit_one, +#endif +}; + +module_pci_driver(serverworks_pci_driver); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("low-level driver for Serverworks OSB4/CSB5/CSB6"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(pci, serverworks); +MODULE_VERSION(DRV_VERSION); -- cgit v1.2.3